Java反射机制
1.反射定义:
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
2.反射作用:
取得任何一个已知名称的class的内部信息。
3.Class对象:
每个类都会产生一个对应的Class对象,也就是保存的.class文件。所有类都是在对其第一次使用时,动态加载到JVM的,当程序创建一个对类的静态成员的引用时,就会加载这个类。Class对象仅在需要的时候才会加载,static初始化是在类加载时进行的。
类加载器首先会检查这个类的Class对象是否已被加载过,如果尚未加载,默认的类加载器就会根据类名查找对应的.class文件。
想在运行时使用类型信息,必须通过Class对象获取,使用功能Class.forName(“对象名或者对象名.class”)。
注意:使用功能”.class”来创建Class对象的引用时,不会自动初始化该Class对象,使用forName()会自动初始化该Class对象。一个类在 JVM 中只会有一个 Class 实例
为了使用类而做的准备工作一般有以下3个步骤:
加载:由类加载器完成,找到对应的字节码,创建一个Class对象
链接:验证类中的字节码,为静态域分配空间
初始化:如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块
4.方法
通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等
查阅 API 可以看到 Class 有很多方法:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
invoke():打破封装。
5.例子
package com.test.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test_Reflect { public int age; private String name; private String sex; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Test_Reflect(int age, String name, String sex) { super(); this.age = age; this.name = name; this.sex = sex; } public Test_Reflect() { super(); } public static void main(String[] args) throws Exception { Test_Reflect tr=new Test_Reflect(); Class c = Class.forName("com.test.reflect.Test_Reflect"); //Class c=tr.getClass(); String className = c.getName(); System.out.println(className); // 获得public属性 Field[] fields = c.getFields(); for (Field field : fields) { System.out.println(field.getName()); } // 获得所有属性(包括私有) Field[] allFields = c.getDeclaredFields(); for (Field field : allFields) { System.out.println(field.getName()); } // 获得public方法,包括 Object 类的一些方法 Method[] methods = c.getMethods(); for (Method method : methods) { System.out.println(method.getName()); } // 获得所有方法 Method[] allMethods = c.getDeclaredMethods(); for (Method method : allMethods) { System.out.println(method.getName()); } // 获得指定属性 Field f1 = c.getField("age"); System.out.println(f1); // 获得指定私有属性 Field f2 = c.getDeclaredField("name"); // 启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消 f2.setAccessible(true); System.out.println(f2); // 创建类的对象 Object p2 = c.newInstance(); // 将 p2 对象的 f2 属性赋值为 Tom,f2 属性即为 私有属性 name f2.set(p2, "Tom"); // 使用反射机制可以打破封装性,导致了java对象的属性不安全。 System.out.println(f2.get(p2)); // 获取构造方法 Constructor[] constructors = c.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor.toString()); } } }
6.使用场景
JDBC原生代码注册驱动,hibernate 的实体类,Spring 的 AOP,逆向代码 ,例如反编译,与注解相结合的框架 例如Retrofit,单纯的反射机制应用框架 例如EventBus 2.x,动态生成类框架 例如Gson等