Java反射专题总结
反射使程序在运行期间可以拿到任意对象的信息,具体是指JVM在程序加载阶段期间将class
文件的成员变量,成员方法,构造函数等很多信息通过类加载器封装到Class
类的实例对象的数据结构里(同一类型的Class
实例对象仅创建一次),以后通过对Class
实例对象的访问,就可以访问到对应的class
文件的所有信息。
Class
类:类型为Class
的类
class
文件:程序里的各种类文件,如String.class
、com.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
的静态变量class
获取
Class cls = String.class; // 多用参数传递,如getConstructor(int.class)根据不同的参数,获得不同的构造器
- 通过实例变量的
getClass()
方法获取
String author = "niuwh";
Class cls = author.getClass();
- 通过
Class
的静态方法Class.forName()
获取
String classPath = "com.niuwh.Blog"; // 多用于配置文件读取
Class cls = Class.forName(classPath); // 需要class文件的具体位置作为参数
Class常用的方法
- 输出cls
System.out.println(cls); // 显示的是cls是哪个类的String对象
System.out.println(cls.getClass()); // 显示的是运行时cls的类型
- 得到包名
System.out.println(cls.getPackage().getName());
- 得到类名
System.out.println(cls.getName()); // 全类名(带包名)
System.out.println(cls.getSimpleName()); // 不带包名
- 通过反射获取/设置属性:属性是包装为
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"); // 设置属性
- 通过反射获取/调用普通方法:方法是包装为
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的静态方法,无须填实例
- 通过反射获取调用构造函数:构造函数由
Constructor
实例保存
// 获取构造方法Integer(int):
Constructor cons1 = Integer.class.getConstructor(int.class); // 获取参数为Int的构造函数
// 同样,也有getConstructors()、getDeclareConstructor()、getDeclareConstructors()
// 调用构造方法:
Integer n1 = (Integer) cons1.newInstance(123);
System.out.println(n1);
- 通过反射获得父类或者父接口的
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