什么是反射?
能够分析类能力的程序称为反射
(
reflective
)
。
反射机制的功能极其强大
,
在下面可以看
到
,
反射机制可以用来
:
• 在运行时分析类的能力。
• 在运行时查看对象, 例如
,
编写一个
toString
方法供所有类使用
。
•
实现通用的数组操作代码
。
•
利用
Method
对象
,
这个对象很像中的函数指针
获取Class对象
在反射之前,我们需要先拿到当前需要反射的类的Class对象,然后通过Class对象调用相关的方法,来达到反射的目的。
获取一个类的Class对象有三种方式:
类名.class
Class<?> clazz1 = MyClass.class;
对象.getClass();
MyClass obj = new MyClass();
Class<?> clazz2 = obj.getClass();
Class.forName("xxx.xxx.xxx.Sxxx"); 这里的字符串是全限定名
String className = "com.example.MyClass";
Class<?> clazz3 = Class.forName(className);
以上都返回的是一个Class类型的对象。
通过
反射实例化对象
public class MyClass {
private String message;
public MyClass() {
this.message = "hello world!";
}
public MyClass(String message) {
this.message = message;
}
public void printMessage() {
System.out.println(message);
}
}
public class Main {
public static void main(String[] args) {
try {
// 获取类对象
Class<?> clazz = MyClass.class;
// 获取无参数的构造方法
Constructor<?> constructor = clazz.getConstructor();
// 使用构造方法实例化对象
MyClass obj = (MyClass) constructor.newInstance();
// 调用对象的方法
obj.printMessage();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在这个示例中,我们有一个名为MyClass
的类,它有一个无参构造方法和一个打印消息的printMessage()
方法。在Main
类中,我们使用反射获取MyClass
的Class
对象。然后,我们使用getConstructor()
方法获取无参数的构造方法。最后,我们使用构造方法的newInstance()
方法实例化一个MyClass
对象,并在该对象上调用printMessage()
方法。
动态创建和操作对象
通过反射,我们可以动态创建对象,并设置和获取对象的字段值,调用对象的方法。
Class<?> clazz = MyClass.class;
// 创建对象
Object obj = clazz.newInstance();
// 获取字段并设置字段值
Field field = clazz.getDeclaredField("myField");
field.setAccessible(true);
field.set(obj, "Hello, Reflection!");
// 调用方法
Method method = clazz.getDeclaredMethod("myMethod");
method.invoke(obj);
// 示例代码
Class<?> clazz = String.class;
Object obj = clazz.newInstance();
Field field = clazz.getDeclaredField("value");
field.setAccessible(true);
field.set(obj, "Hello, Reflection!");
Method method = clazz.getDeclaredMethod("length");
Object result = method.invoke(obj);
System.out.println(result); // 输出:18
动态扩展和修改类
反射还允许我们动态地添加新的字段和方法,以及修改现有字段和方法的访问权限。
Class<?> clazz = MyClass.class;
// 动态添加新字段
Field newField = new FieldBuilder()
.withName("newField")
.withType(String.class)
.withModifiers(Modifier.PRIVATE)
.build();
ClassUtils.addField(clazz, newField);
// 动态添加新方法
Method newMethod = new MethodBuilder()
.withName("newMethod")
.withReturnType(void.class)
.withModifiers(Modifier.PUBLIC)
.withBody("System.out.println(\"New Method\");")
.build();
ClassUtils.addMethod(clazz, newMethod);
// 修改现有字段的访问权限
Field field = clazz.getDeclaredField("myField");
field.setAccessible(true);
// 修改现有方法的访问权限
Method method = clazz.getDeclaredMethod("myMethod");
method.setAccessible(true);
// 示例代码
Class<?> clazz = String.class;
Field newField = new FieldBuilder()
.withName("newField")
.withType(String.class)
.withModifiers(Modifier.PRIVATE)
.build();
ClassUtils.addField(clazz, newField);
Field field = clazz.getDeclaredField("newField");
field.setAccessible(true);
field.set(obj, "New Field");
反射的应用
- 使用JDBC时,如果要创建数据库的连接,则需要先通过反射机制加载数据库的驱动程序 ;
- 多数框架都支持注解/XML配置,从配置中解析出来的类是字符串,需要利用反射机制实例化;
- 面向切面编程(AOP)的实现方案,是在程序运行时创建目标对象的代理类,这必须由反射机制来实现
反射在许多应用场景中发挥着重要作用,包括框架和库的设计与扩展、配置文件的解析和加载、注解处理器和自定义注解、单元测试和调试工具,以及Java反序列化和序列化等方面。