实现反射,实际就是得到 Class 对象,使用 java.lang.Class 这个类。这是反射机制的起源,当一个类被加载后,Java虚拟机会自动产生一个 Class 对象。
以下是三种获取 Class 对象的方法,以 ReflectBean 类为例:
package com.example.java;
public class ReflectBean {
private String name;
private int age;
public ReflectBean() {
}
public ReflectBean(String name) {
this.name = name;
}
public ReflectBean(String name, int age) {
this.name = name;
this.age = age;
}
}
//1.反射机制获取,forName 中是类的全路径类名
Class c1 = Class.forName("com.example.java.ReflectBean");
//2.自身类属性获取
Class c2 = Reflect.class;
//3.通过getClass 方法获取
Class c3 = new Reflect().getClass();
以上三种 Class 初始化的区别在于:
Class.forName —— 会让 ClassLoader 装载类,并进行类的初始化。
getClass —— 返回类对象运行时真正所指对象实例的 Class 对象。
.class —— ClassLoader 装载入内存,不对类进行初始化操作。
反射之创建实例:
Class c = Class.forName("com.example.java.ReflectBean");
//无参创建
c.newInstance();
//有参创建
//getConstructor() 会返回一个 Constructoor 对象。它反映了此 Class 对象所表示的类指定的公共构造方法。
//getConstructor() 不能访类的问私有构造。错误信息:NoSuchMethodException
Constructor<?> csr = c.getConstructor(String.class, int.class);
Object o = csr.newInstance("name", 18);
//反射创建对象,可以使用 Class.newInstance() 和 Contructor.newInstance() 两种方法
//不同之处在于 Class.newInstance() 的使用受到严格限制,对应的 Class 类中必须存在一个无参数的构造方法,并且必须有访问权限。
//而Contructor.newInstance() 适应任何类型的构造方法,无论是否有参数都可以调用,只需要使用 setAccessible() 控制访问验证即可。
反射之Field对象:
Class c = Class.forName("com.example.java.ReflectBean");
//获取类中的属性
//Field 类描述的是属性对象,其中可以获取到很多属性的信息,包括名字,属性类型,属性的注解。
Field nameField = c.getDeclaredField("name");
//取消封装,特别是可以取消私有字段访问权限。
//在安全管理器中会使用 checkPermission 方法来检查权限,而 setAccessible(true) 并不是将方法的权限修改为 public,而是取消 Java 的权限控制检查。所以即使是 public 方法,其 accessible 属性默认也是 false。
nameField.setAccessible(true);
//修改属性的值
Object o = c.newInstance();
nameField.set(o, "名称");
//获取属性的修饰符
//getModifiers() 返回的是一个 int 类型的返回值,代表类,成员变量,方法的修饰符。
String priv = Modifier.toString(nameField.getModifiers());
反射之Method对象:
Class c = Class.forName("com.example.java.ReflectBean");
//获取类中的方法
Method m = c.getDeclaredMethod("setName", String.class);
//调用方法
Object o = c.newInstance();
m.setAccessible(true);
m.invoke(o, "name");
package com.example.java;
public class ReflectBean<T> {
public void printResult(T t){
System.out.print("泛型方法");
}
}
Class c = Class.forName("com.example.java.ReflectBean");
Object o = c.newInstance();
//当一个方法中有泛型参数时,编译器会自动类型向上转型,T 向上转型是 Object,所以实际上 ReflectBean<T> 类中是 printResult(Object t)。
Method m = c.getDeclaredMethod("printResult", Object.class);
m.invoke(o, "泛型");
获取父类Class:
Class c = Class.forName("com.example.java.ReflectBean");
Class superClz = c.getSuperclass();