1.、概述
Java反射机制指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。
Java的反射机制允许编程人员在对类未知的情况下,获取类相关信息的方式变得更加多样灵活,调用类中相应方法,是Java增加其灵活性与动态性的一种机制
- 好处:
- 可以在程序运行过程中,操作这些对象。
- 可以解耦,提高程序的可扩展性。
2、功能
- 在运行时判断任意的一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
优点:
可以实现动态创建对象和编译,体现出很大的灵活性
Public final Class getClass();
以上的方法返回值
获取Class对象的多种方式
//对象.getClass():getClass()方法在Object类中定义着。
//多用于对象的获取字节码的方式
person.getClass();
//Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
//多用于配置文件,将类名定义在配置文件中。读取文件,加载类
Class.forName();
//类名.class:通过类名的属性class获取
//多用于参数的传递
Student.class;
//只对包装类有效
Integer.Type;
//获得父类类型
Class.getSuperClass;
可以有反射对象的类型
- 外部类
- 接口
- 数组
- 在数组中,和长度无关,只要是一个维度并且类型相同,就是同一个class
- 二维数组
- 注解
- 枚举类型
- 基本数据类型
- void
- 反射对象本身
3.类的加载与ClassLoader的理解
类的主动引用(一定会发生类的初始化)
双亲委派机制
如果一个类加载器(ClassLoader)收到了类加载的请求,它首先不 会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如 此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完 成这个加载请求(它的搜索范围中没有找到所需要加载的类)时,子加载器才会尝试自己去加载。
通过反射获取运行时类的完整结构
-
Load:加载
- 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构, 然后生成一个代表这个类的java.lang.Class对象.
-
Link:链接 :将Java类的二进制代码合并到JVM的运行状态之中的过程。
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
-
Initialize:初始化
- 初始化: 执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中所有类变量的赋值动作和静态 代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步:
3.反射的功能
3.1、Class对象功能:
获取运行时类的完整结构:
1. 获取成员变量们
Field[] getFields() //获取所有public修饰的成员变量
Field getField(String name) //获取指定名称的 public修饰的成员变量
Field[] getDeclaredFields() //获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name)
2. 获取构造方法们
Constructor<?>[] getConstructors()
Constructor<T> getConstructor(类<?>... parameterTypes)
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()
3. 获取成员方法们:
Method[] getMethods()
Method getMethod(String name, 类<?>... parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
4. 获取全类名
String getName()
例:
public class Demo2 {
public static void main(String[] args) throws Exception {
Class class1 = Class.forName("com.xupt.demo1.Student");
Method[] methods = class1.getMethods();
Method[] declaredMethods = class1.getDeclaredMethods();
System.out.println(methods.length);
System.out.println(declaredMethods.length);
Field[] fields = class1.getFields();
Field[] declaredFields = class1.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
Field name = class1.getDeclaredField("name");
System.out.println(name);
Constructor declaredConstructor = class1.getDeclaredConstructor();
System.out.println(declaredConstructor.getName());
ClassLoader classLoader = class1.getClassLoader();
Constructor[] constructors = class1.getConstructors();
Constructor[] declaredConstructors = class1.getDeclaredConstructors();
}
}
Field:成员变量
操作:
设置值
void set(Object obj, Object value)
获取值
get(Object obj)
忽略访问权限修饰符的安全检查
setAccessible(true):
- Method和Field、Constructor对象都有setAccessible()方法。
- setAccessible作用是启动和禁用访问安全检查的开关。参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
- 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
- 使得原本无法访问的私有成员也可以访问
- 参数值为false则指示反射的对象应该实施Java语言访问检查
Constructor:构造方法
创建对象:
- T newInstance(Object… initargs)
- 如果使用空参数构造方法创建对象,操作可以简化:Class对象的newInstance方法
Method:方法对象
- 执行方法:
- Object invoke(Object obj, Object… args)
- 获取方法名称:
- String getName:获取方法名