反射是 Java 提供的一种强大机制,允许程序在运行时获取类的信息和操作对象。它的原理主要基于 Java 的类加载机制和 java.lang.reflect 包中的类。以下是反射的核心原理及其工作方式:
1. 类加载机制
- 类加载器:Java 使用类加载器来加载类文件。类加载器将类的字节码加载到 JVM 中,并为每个类创建一个
Class对象。 - Class 对象:每个类在 Java 中都有一个对应的
Class对象,包含了类的结构信息(如字段、方法、构造函数等)。
2. java.lang.reflect 包
-
反射的核心 API 位于
java.lang.reflect包中,主要包括以下几个类:Class:表示类的结构,可以获取类的信息。Field:表示类的字段,可以获取和修改字段的值。Method:表示类的方法,可以调用方法。Constructor:表示类的构造函数,可以创建对象。
3. 反射的基本操作
-
获取 Class 对象:
- 通过类的名字、实例对象或类字面量获取
Class对象。
Class<?> clazz = MyClass.class; // 通过类字面量 Class<?> clazz = obj.getClass(); // 通过实例对象 Class<?> clazz = Class.forName("com.example.MyClass"); // 通过类名 - 通过类的名字、实例对象或类字面量获取
-
获取信息:
- 使用
Class对象获取构造函数、方法和字段的信息。
Method[] methods = clazz.getDeclaredMethods(); Field[] fields = clazz.getDeclaredFields(); - 使用
-
创建实例:
- 通过
Constructor对象创建类的实例。
Constructor<?> constructor = clazz.getConstructor(); Object instance = constructor.newInstance(); - 通过
-
调用方法:
- 使用
Method对象调用类的方法。
Method method = clazz.getMethod("myMethod", String.class); method.invoke(instance, "Hello"); - 使用
-
访问字段:
- 使用
Field对象获取或修改字段的值。
- 使用
```java
Field field = clazz.getDeclaredField("myField");
field.setAccessible(true); // 允许访问私有字段
Object value = field.get(instance);
```
4. 性能和安全性
- 性能:反射操作相对较慢,因为它涉及到动态查找和方法调用,因此应谨慎使用,尤其是在性能敏感的场合。
- 安全性:反射可以访问私有成员,因此在使用时需要注意安全性和数据保护。
总结
反射是 Java 中一种强大的灵活性机制,允许程序在运行时动态地获取类的信息和操作对象。通过反射,开发者能够实现高度可配置和可扩展的应用程序,但也需要注意其带来的性能和安全性问题。
最终练习
package reflect;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* @Author xushupeng
* @Date 2024-12-13 16:09
* 注意看配置文件
*/
public class 反射练习结合配置文件动态创建 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.读取配置文件
Properties properties = new Properties();
FileInputStream fis=new FileInputStream("src/reflect/prop.properties");
properties.load(fis);
fis.close();
System.out.println(properties);
//2.获取配置文件中的全类名
String classname=properties.getProperty("classname");
System.out.println(classname);
//获取配置文件的方法名
String methodName=properties.getProperty("method");
System.out.println(methodName);
//根据全类名 获取字节码文件对象
Class clazz=Class.forName(classname);
//获取构造方法 getDeclaredConstructor() 方法用于获取该类的默认构造函数(即无参数的构造函数) 如果方法中含有参数 那么就可以指定构造函数
Constructor con = clazz.getDeclaredConstructor(String.class, int.class);
Object o=con.newInstance("xsp",22);
System.out.println(o);
Student student=(Student)o;//向下转型
student.info();
//获取成员方法并运行
Method method = clazz.getDeclaredMethod(methodName);
method.setAccessible(true);
method.invoke(o);
}
}
配置文件如下