反射有两种显著作用:
- 反编译:.class —> .java
- 通过反射机制访问Java对象中的属性,方法,构造方法等。
反射机制需要使用的类:
- java.lang.Class —— 类的创建。
- java.lang.reflect.Constructor —— 反射类中的构造方法。
- java.lang.reflect.Field —— 反射类中的属性。
- java.lang.reflect.Method —— 反射类中的方法。
- java.lang.reflect.Modifier —— 反射类中的修饰符信息。
实现反射,实际就是得到 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 {
static void printResult(){
System.out.print("rsult: null");
}
static void printResult(String value){
System.out.print("result: "+ value);
}
}
Class c = Class.forName("com.example.java.ReflectBean");
//关键在于Method.invoke() 的第一个参数,static 方法属于类本身,所以不需要填写对象,填 null 即可。
Method m1 = c.getDeclaredMethod("printResult");
m1.invoke(null);
Method m2 = c.getDeclaredMethod("printResult", String.class)
m2.invoke(null, "ok");
泛型方法调用:
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();
反射方法访问权限表:
反射获取构造方法体
方法 | 本 Class | 父 Class |
getConstructor | public | public |
getDeclaredConstructor | public, procted, private | no |
getConstructors | public | public |
getDeclaredConstructors | public, procted, private | no |
反射获取属性修饰符
方法 | 本 Class | 父 Class |
getField | public | public |
getDeclaredField | public, procted, private | no |
getFields | public | public |
getDeclaredFields | public, procted, private | no |
反射获取方法体
方法 | 本 Class | 父 Class |
getMethod | public | public |
getDeclaredMethod | public, procted, private | no |
getMethods | public | public |
getDeclaredMethods | public, procted, private | no |