反射有两种显著作用:

  • 反编译:.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