文章目录
- 1.反射的定义
- 2. 认识反射的关键API
- 2.1 Class
- 2.2 Field
- 2.3 Method
- 2.4 Constructor
- 3. 示例代码讲解与分析
- 4. 编写反射示例代码的步骤
- 4.1 定义测试类
- 4.2 编写主程序,使用反射获取信息
- 4.3 通过反射创建对象并调用方法
- 5. 总结
- 6.今日生词
Java反射笔记
1.反射的定义
- 反射是什么?
Java反射是一种在运行时动态获取类的结构信息并操作对象的机制。通过反射,你可以:- 获取类信息:在程序运行时动态加载类,检查类的属性、方法和构造函数。
- 动态操作:可以动态调用对象的方法、修改对象的属性(即使是私有成员),甚至创建新的对象实例。
- 应用场景:
- 框架开发(如Spring、Hibernate)常常利用反射实现依赖注入、动态代理和数据绑定。
- 插件化开发:根据配置动态加载类,实现模块化扩展。
2. 认识反射的关键API
2.1 Class
- 作用:代表一个类或接口的运行时类型信息。
- 获取方式:
- 使用实例的
getClass()
方法:Object obj = new Person(); Class<?> cls = obj.getClass();
- 使用静态方法
Class.forName("完整类名")
:Class<?> cls = Class.forName("com.example.Person");
- 使用实例的
- 常用方法:
getName()
:获取类的全限定名。getDeclaredFields()
:获取所有声明的字段(包括私有字段)。getDeclaredMethods()
:获取所有声明的方法。getConstructors()
和getDeclaredConstructors()
:获取公共构造函数或所有构造函数。
2.2 Field
- 作用:代表类的成员变量(字段)。
- 常用方法:
getName()
:返回字段名称。get(Object obj)
:获取指定对象上此字段的值。set(Object obj, Object value)
:修改指定对象上此字段的值。setAccessible(true)
:当字段是私有时,允许通过反射访问或修改其值。
- 注意事项:使用
setAccessible(true)
时要注意安全性和封装性,最好在必要时才使用。
2.3 Method
- 作用:代表类中的方法。
- 常用方法:
getName()
:获取方法名称。invoke(Object obj, Object... args)
:在指定对象上调用此方法,传递必要的参数。getParameterTypes()
:获取方法参数类型数组。- 使用场景:动态调用对象方法,或在运行时根据方法名称决定调用哪个方法。
2.4 Constructor
- 作用:代表类的构造函数。
- 常用方法:
newInstance(Object... initargs)
:利用构造函数创建新实例,传入必要参数。getParameterTypes()
:获取构造函数的参数类型。
- 使用场景:动态创建对象实例,尤其是在编写通用工厂模式或插件式架构时非常有用。
3. 示例代码讲解与分析
下面是一段简单的示例代码,展示如何使用反射获取一个类的结构信息。假设我们有一个简单的 Person 类。
示例代码
// 定义一个简单的Person类
public class Person {
private String name;
private int age;
// 构造函数
public Person() {
this.name = "Default";
this.age = 0;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 方法:打印信息
public void sayHello() {
System.out.println("Hello, my name is " + name);
}
}
反射获取类信息的示例
import java.lang.reflect.*;
public class ReflectionDemo {
public static void main(String[] args) {
try {
// 1. 获取Person类的Class对象
Class<?> personClass = Class.forName("Person");
// 2. 获取类的名称
System.out.println("类名称:" + personClass.getName());
// 3. 获取所有构造函数
Constructor<?>[] constructors = personClass.getDeclaredConstructors();
System.out.println("构造函数:");
for (Constructor<?> constructor : constructors) {
System.out.println(" " + constructor);
}
// 4. 获取所有字段(包括私有字段)
Field[] fields = personClass.getDeclaredFields();
System.out.println("字段:");
for (Field field : fields) {
System.out.println(" " + field.getName());
}
// 5. 获取所有方法
Method[] methods = personClass.getDeclaredMethods();
System.out.println("方法:");
for (Method method : methods) {
System.out.println(" " + method.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
分析
- Class.forName(“Person”):动态加载
Person
类,通过其完全限定名获得Class
对象。 - 获取构造函数:调用
getDeclaredConstructors()
返回该类所有构造函数,并输出构造函数的签名。 - 获取字段:调用
getDeclaredFields()
,即使字段为私有也能获取到。通过field.getName()
输出每个字段的名称。 - 获取方法:调用
getDeclaredMethods()
得到类中所有声明的方法,输出方法名称以便了解类提供了哪些操作。
4. 编写反射示例代码的步骤
4.1 定义测试类
创建一个名为 Person
的类,包含如下内容:
- 字段:
name
(String)、age
(int)。 - 构造函数:无参构造函数和带参构造函数。
- 方法:例如
sayHello()
用于输出欢迎信息。
4.2 编写主程序,使用反射获取信息
1.加载类:使用 Class.forName("Person")
获取 Class
对象。
2.获取构造函数:使用 getDeclaredConstructors()
获取所有构造函数。
3.获取字段:使用 getDeclaredFields()
获取所有字段,必要时调用 setAccessible(true)
访问私有字段。
4.获取方法:使用getDeclaredMethods()
获取所有方法。
4.3 通过反射创建对象并调用方法
- 实例化对象:使用获取到的构造函数(如带参构造函数)调用 newInstance() 创建 Person 对象。
- 修改字段:如果需要,可以通过反射修改私有字段的值。例如,调用 field.setAccessible(true) 后,再使用
field.set(personInstance, "新的名字")
。 - 调用方法:使用
Method.invoke(object, args...)
来调用sayHello()
方法,并观察控制台输出。
示例代码扩展:创建对象并调用方法
import java.lang.reflect.*;
public class ReflectionDemoExtended {
public static void main(String[] args) {
try {
// 1. 加载Person类的Class对象
Class<?> personClass = Class.forName("Person");
// 2. 获取带参构造函数,并创建对象
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
Object personInstance = constructor.newInstance("Alice", 25);
// 3. 修改私有字段(假设需要修改name)
Field nameField = personClass.getDeclaredField("name");
nameField.setAccessible(true); // 允许访问私有字段
nameField.set(personInstance, "Bob");
// 4. 调用sayHello方法
Method sayHelloMethod = personClass.getDeclaredMethod("sayHello");
sayHelloMethod.invoke(personInstance);
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码说明
- 创建对象:通过
getConstructor(String.class, int.class) ``获取带参构造函数,然后调用
newInstance(“Alice”, 25) `创建对象。 - 修改字段:通过
getDeclaredField("name")
获取name
字段,设置为可访问后,用set()
方法修改对象的name
值为 “Bob”。 - 调用方法:获取
sayHello
方法,并调用invoke()
执行该方法,观察输出验证修改后的值。
5. 总结
- 反射的优势:可以在运行时动态操作对象和类,灵活应对各种需求(如插件化、依赖注入)。
- 需要注意的点:
- 反射操作可能破坏封装性,使用时需要谨慎。
- 反射会有一定的性能损耗,不建议在性能敏感的场景中大量使用。
6.今日生词
1.tongue 2.circunstance 3.tension 4.economist 5.accommodate