如何理解反射
基础
关键问题
本文主要的目标是回答以下问题:
- 创建对象可以使用new,为什么我还需要反射?
- 如何使用反射创建未知类的对象?调用未知类的方法?
反射的定义
学习反射时,我们最不理解的一个问题就是,我要创建对象,直接使用new就可以了,为什么还需要反射?通过下面的定义,应该能够回答这个问题。
- 【核心定义】java反射机制就是对于任意一个未知的类,都能够创建其对象,调用其方法。
- 反射和new的区别:new只能针对编译阶段已经存在的类,如果在编译时这个类不存在,就无法创建对象,因为你都不知道该new谁。而使用反射,在编译阶段这个类不需要存在,只要在运行时要创建对象的时候存在即可。简单来说,new只能为已知的类创建对象,反射可以为未知的类创建对象。
上面的描述是一个比较通俗的说法,比较专业的说法是,new创建对象是静态编译,而反射创建对象是动态编译的过程。动态和静态分别代表的就是运行阶段和编译阶段。
反射的作用
- 反射的核心作用,就是能够为任意未知的类创建对象,换句话说,就是为别人的类创建对象。
什么情况下我会用到反射?
- 我要为一个类创建对象,但是我事先不知道这个类长什么样,可以使用反射。(IOC)
- 我要增强一个方法,但是我事先不知道这个方法长什么样,可以用反射。(AOP)
为什么说“反射是Java框架的基石”?
- 首先要理解框架的运行模式:框架是一套封装好的工具,然后用户基于框架开发,设计了各种类。这些类框架实现是不知道的,但是又必须将这些类实例化,并且调用其方法,最终发挥作用。
- 所以说,框架要解决的第一个问题就是:如何为别人写的类创建对象?而在上面的定义中可以发现,反射刚好就是解决这个问题的。因此,就有了“反射是java框架的基石”这一说法。
反射的常见用法
根据类名称创建对象
这个过程类似Spring中的@Autowired
/**
* 1、首先根据类名称获取class对象
* 2、然后实例化一个对象
*/
Class<Person> clazz = (Class<Person>) Class.forName("bean.Person");
Person person = clazz.newInstance();
调用类的构造方法
/**
* 1、首先根据类名称获取class对象
* 2、然后获取构造函数对象,指定参数类型
* 3、调用构造函数对象的newInstance方法
*/
Class<Person> clazz = (Class<Person>) Class.forName("bean.Person");
Constructor<Person> constructor = clazz.getConstructor(String.class);
Person zhangsan = constructor.newInstance("zhangsan");
调用类的成员方法
/**
* 1、首先根据类名称获取class对象
* 2、然后获取成员方法对象,指定方法名称和参数类型列表
* 3、调用成员方法,指定方法所属的对象,输入方法的参数
*/
Class<Person> clazz = (Class<Person>) Class.forName("bean.Person");
Method hello = clazz.getMethod("hello", String.class);
Person person = clazz.newInstance();
hello.invoke(person, "china");
操作成员变量
/**
* 1、首先根据类名称获取class对象
* 2、获取成员变量对象
* 3、为成员变量赋值,指定所属的对象
*/
Class<Person> clazz = (Class<Person>) Class.forName("bean.Person");
Field name = clazz.getField("name");
Person person = clazz.newInstance();
name.set(person, "zhangsan");
总结
结论
- 通过反射的定义,现在基本理解了new和反射的区别,两者分别适用于不同的场景,通俗来讲,new的作用是实例化自己的类,而反射的作用是实例化任何人的类,主要用于实例化别人的类。
- 通过简单的示例代码,演示了反射的常见用法,对于一些特殊情况的用法,比如私有方法的调用,大同小异,就不进行详细描述了。