反射:框架设计的灵魂
框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。简单理解为:将 Java 类的各个组成部分封装为一个个的 Java 对象,这就是反射机制
-
好处:
-
可以在程序运行过程中,操作这些对象。
-
可以解耦,提高程序的可扩展性。
-
获取Class对象得方式:
1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. 类名.class:通过类名的属性class获取
* 多用于参数的传递
3. 对象.getClass():getClass()方法在 Object 类中定义着。
* 多用于对象的获取字节码的方式
- 结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
获取功能:
-
获取成员变量们
* Field[] getFields() :获取所有public修饰的成员变量 * Field getField(String name) 获取指定名称的 public修饰的成员变量 * Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符 * Field getDeclaredField(String name)
-
获取构造方法们
* Constructor<?>[] getConstructors() * Constructor<T> getConstructor(类<?>... parameterTypes) * Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) * Constructor<?>[] getDeclaredConstructors()
-
获取成员方法们:
* Method[] getMethods() * Method getMethod(String name, 类<?>... parameterTypes) * Method[] getDeclaredMethods() * Method getDeclaredMethod(String name, 类<?>... parameterTypes)
-
获取全类名
* String getName()
Field :成员变量
-
操作:
1. 设置值 * void set(Object obj, Object value) 2. 获取值 * get(Object obj)
Constructor:构造方法
-
创建对象:
* T newInstance(Object... initargs)
- 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
Method:方法对象
-
执行方法:
* Object invoke(Object obj, Object... args)
-
获取方法名称:
* String getName:获取方法名
-
getName、getCanonicalName 与 getSimpleName 的区别:
* getSimpleName:只获取类名 * getName:类的全限定名,jvm中Class的表示,可以用于动态加载Class对象,例如Class.forName。 * getCanonicalName:返回更容易理解的表示,主要用于输出(toString)或log打印,大多数情况下和getName一样,但是在内部类、数组等类型的表示形式就不同了。
小结
- 反射类及反射方法的获取,都是通过从列表中搜寻查找匹配的方法,所以查找性能会随类的大小方法多少而变化;
- 每个类都会有一个与之对应的Class实例,从而每个类都可以获取method反射方法,并作用到其他实例身上;
- 反射也是考虑了线程安全的,放心使用;
- 反射使用软引用relectionData缓存class信息,避免每次重新从jvm获取带来的开销;
- 反射调用多次生成新代理Accessor, 而通过字节码生存的则考虑了卸载功能,所以会使用独立的类加载器;
- 当找到需要的方法,都会copy一份出来,而不是使用原来的实例,从而保证数据隔离;
- 调度反射方法,最终是由jvm执行invoke0()执行;