反射的原理
类加载器(ClassLoader):
类加载器负责读取.class文件,并将它们加载到Java虚拟机(JVM)中。每个Java程序至少使用三个类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和系统类加载器(System ClassLoader)。
类对象(Class Object):
每个加载到JVM中的类都有一个对应的java.lang.Class
对象。这个对象包含了类的元数据,如类的名称、字段、方法、构造函数等。
反射 API:
Java 反射 API 提供了一系列的类和接口来操作Class
对象。主要的类包括:
Class
:代表类和接口的静态类型信息。Field
:代表类的成员变量。Method
:代表类的方法。Constructor
:代表类的构造函数。Array
:提供动态创建和访问Java数组。
获取 Class 对象:
可以通过多种方式获取一个类的Class
对象:
- 直接使用类字面量:
Class<?> clazz = MyClass.class;
- 通过实例对象的
getClass()
方法:MyClass obj = new MyClass(); Class<?> clazz = obj.getClass();
- 使用类加载器的
loadClass()
方法。
访问类成员:
一旦有了Class
对象,就可以使用反射 API 访问类的成员,如字段、方法和构造函数。这包括:
- 获取成员列表:
Class
对象的getFields()
、getMethods()
和getConstructors()
方法。 - 访问特定成员:
getDeclaredField()
、getDeclaredMethod()
和getDeclaredConstructors()
方法,这些方法可以访问包括私有成员在内的所有成员。
修改访问控制**:
使用Field
、Method
和Constructor
对象的setAccessible(true)
方法可以修改Java语言的访问控制,允许反射访问私有成员。
创建和操作对象**:
使用Class
对象的newInstance()
方法可以创建类的实例。对于没有无参构造函数的类,可以使用Constructor
对象的newInstance()
方法。
调用方法和访问字段**:
使用Method
对象的invoke()
方法可以在对象上调用方法。使用Field
对象的get()
和set()
方法可以读取和修改字段的值。
泛型和数组的特殊处理**:
由于Java的类型擦除,泛型信息在运行时不可用。数组的处理稍有不同,因为数组是固定类型的。
异常处理**:
反射操作可能会抛出多种异常,如ClassNotFoundException
、IllegalAccessException
、InstantiationException
、NoSuchFieldException
、NoSuchMethodException
等。