Java反射专题总结

反射使程序在运行期间可以拿到任意对象的信息,具体是指JVM在程序加载阶段期间将class文件的成员变量,成员方法,构造函数等很多信息通过类加载器封装到Class类的实例对象的数据结构里(同一类型的Class实例对象仅创建一次),以后通过对Class实例对象的访问,就可以访问到对应的class文件的所有信息。

Class类:类型为Class的类

class文件:程序里的各种类文件,如String.classcom.niuwh.blog.Main.class

Class实例对象:Class类的实例,仅JVM可以初始化实例

public final class Class{   // Class的定义
    private Class(){}
    // ...
}

如,加载String类时,先读取String字节码文件到内存中,然后由类加载器为该String类创建对应的Class实例对象,该实例对象里保存了String类里的很多信息。

在IDEA里可以光标选择Class类,通过Ctrl+H即可查看Class的继承关系与实现接口类型(如图所示),Class类位于java.lang包,继承于Object类,其他是实现的接口类。

Class类继承关系

寻找Class实例对象的方法

  1. 通过Class的静态变量class获取
Class cls = String.class;   // 多用参数传递,如getConstructor(int.class)根据不同的参数,获得不同的构造器
  1. 通过实例变量的getClass()方法获取
String author = "niuwh";
Class cls = author.getClass();
  1. 通过Class的静态方法Class.forName()获取
String classPath = "com.niuwh.Blog";    // 多用于配置文件读取
Class cls = Class.forName(classPath);   // 需要class文件的具体位置作为参数

Class常用的方法

  1. 输出cls
System.out.println(cls);    // 显示的是cls是哪个类的String对象
System.out.println(cls.getClass());     // 显示的是运行时cls的类型
  1. 得到包名
System.out.println(cls.getPackage().getName());
  1. 得到类名
System.out.println(cls.getName());          // 全类名(带包名)
System.out.println(cls.getSimpleName());    // 不带包名
  1. 通过反射获取/设置属性:属性是包装为Field实例保存的
People people = new People();
Field author = cls.getField("name");            // 只能获取publuic字段
Field author = cls.getDeclaredField("name");    // 共有私有字段都可以获取

System.out.println(author.get(people));     // 获得属性值
author.setAccessible(true);                 // 关闭安全通道检查,即可访问private属性值
author.set(people,"nwh");                   // 设置属性
  1. 通过反射获取/调用普通方法:方法是包装为Methods实例保存的
Class stdClass = Student.class;
stdClass.getMethod("getScore", String.class);       // 获取public方法getScore,参数为String
stdClass.getMethod("getScore");                     // 获取public方法getScore,无参数
stdClass.getDeclaredMethod("getGrade", int.class);  // 可以获取私有方法,参数为int
stdClass.getMethods();          // 获取所有私有方法
stdClass.getDeclaredMethods();  // 获取所有方法

Methods m = stdClass.getMethod("getScore", String.class);
m.setAccessible(true);  // 若m是私有方法,需执行本局后才能访问
m.getName();            // 返回方法名称
m.getReturnType()       // 返回返回值类型
m.getModifiers()        // 返回修饰符类型
    
Student student = new Student;
int age = m.invoke(student,"99");   // 在student实例上调用该方法
int n = m.invoke(null,"123123");    // 表示m为Student的静态方法,无须填实例
  1. 通过反射获取调用构造函数:构造函数由Constructor实例保存
// 获取构造方法Integer(int):
Constructor cons1 = Integer.class.getConstructor(int.class);    // 获取参数为Int的构造函数
// 同样,也有getConstructors()、getDeclareConstructor()、getDeclareConstructors()

// 调用构造方法:
Integer n1 = (Integer) cons1.newInstance(123);
System.out.println(n1);
  1. 通过反射获得父类或者父接口的Class实例
Class cls = String.class;
Class cls.getSuperclass();  // class java.lang.Object 得到父类接口

Class[] is = cls.getInterfaces();   // 得到了多个父类接口
for(Class i:is){  
    System.out.println(i);     // interface java.io.Serializable
}                              // interface java.lang.Comparable
                               // interface java.lang.CharSequence
                               // interface java.lang.constant.Constable
                               // interface java.lang.constant.ConstantDesc