java反射允许程序在运行时检查和修改自身结构,通过java.lang.reflect包实现。1.获取class对象有三种方式:class.forname()、类名.class、对象.getclass()。2.创建对象可使用newinstance()或指定构造函数。3.访问字段需获取field对象并设置setaccessible(true)以访问私有字段。4.调用方法需获取method对象并使用invoke()执行。反射广泛应用于spring依赖注入、orm映射、junit测试、动态代理及序列化。性能问题可通过缓存、减少反射调用、代码生成等方式优化。安全性问题可通过安全管理器、代码审查、最小权限原则避免。反射还可与泛型结合,用于创建泛型实例及获取类型信息。class.forname()依赖classloader加载类,过程包括检查是否已加载、委托父类加载、尝试加载并定义类。反射虽强大但需权衡性能与安全,合理使用能提升程序灵活性。

Java反射,简单来说,就是让你的程序在运行时能够检查甚至修改自身的结构。这听起来有点像科幻电影,但它确实是Java语言的一项强大特性。反射不仅仅是“看看”一个类有什么,更重要的是,它允许你在不知道类具体信息的情况下,创建对象、调用方法、访问属性。

解决方案
反射的核心在于java.lang.reflect包。这个包提供了一系列的类,如Class、Method、Field、Constructor等,它们分别代表了类、方法、字段、构造函数等程序元素。
立即学习“Java免费学习笔记(深入)”;

获取Class对象: 这是反射的起点。你可以通过以下几种方式获取Class对象:
Class.forName("类的全限定名"):最常用的方式,动态加载类。类名.class:适用于编译时已知的类。对象.getClass():适用于已有对象实例。try {
Class<?> clazz = Class.forName("com.example.MyClass");
// 或者
Class<?> clazz2 = MyClass.class;
// 或者
MyClass obj = new MyClass();
Class<?> clazz3 = obj.getClass();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}创建对象: 通过Class对象,你可以创建类的实例。

clazz.newInstance():调用类的无参构造函数。 (已过时,不推荐)clazz.getConstructor(参数类型...).newInstance(参数值...):调用指定的构造函数。try {
Class<?> clazz = Class.forName("com.example.MyClass");
// 使用无参构造函数
// MyClass obj = (MyClass) clazz.newInstance(); //已过时,不推荐
// 使用带参数的构造函数
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
MyClass obj2 = (MyClass) constructor.newInstance("Hello", 123);
} catch (Exception e) {
e.printStackTrace();
}访问和修改字段: 可以获取类的字段,并读取或修改它们的值。
clazz.getField("字段名"):获取公共字段。clazz.getDeclaredField("字段名"):获取所有字段(包括私有字段)。field.setAccessible(true):允许访问私有字段。field.get(对象):获取字段的值。field.set(对象, 值):设置字段的值。try {
Class<?> clazz = Class.forName("com.example.MyClass");
MyClass obj = new MyClass();
// 获取私有字段
Field privateField = clazz.getDeclaredField("privateField");
privateField.setAccessible(true); // 允许访问私有字段
// 获取字段的值
String fieldValue = (String) privateField.get(obj);
System.out.println("Private field value: " + fieldValue);
// 设置字段的值
privateField.set(obj, "New Value");
System.out.println("Private field new value: " + privateField.get(obj));
} catch (Exception e) {
e.printStackTrace();
}调用方法: 获取类的方法,并执行它们。
clazz.getMethod("方法名", 参数类型...):获取公共方法。clazz.getDeclaredMethod("方法名", 参数类型...):获取所有方法(包括私有方法)。method.setAccessible(true):允许访问私有方法。method.invoke(对象, 参数值...):调用方法。try {
Class<?> clazz = Class.forName("com.example.MyClass");
MyClass obj = new MyClass();
// 获取私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod", String.class);
privateMethod.setAccessible(true); // 允许访问私有方法
// 调用方法
String result = (String) privateMethod.invoke(obj, "Input");
System.out.println("Private method result: " + result);
} catch (Exception e) {
e.printStackTrace();
}反射在很多框架和库中都有广泛的应用,例如:
@Test注解的方法,并通过反射来执行这些方法。反射虽然强大,但它也有一个明显的缺点:性能开销。由于反射需要在运行时进行类型检查和方法查找,因此它的性能通常比直接调用慢得多。但也不是不能解决,可以尝试以下方法:
Method对象、Field对象等。这样可以避免重复的查找和类型检查。可以使用ConcurrentHashMap等线程安全的缓存结构。setAccessible(true): 访问私有成员时,setAccessible(true)只需要调用一次,后续的访问可以直接使用缓存的Field或Method对象。反射打破了Java的封装性,允许访问和修改对象的私有成员。这可能导致安全问题,例如:
为了避免这些安全问题,可以采取以下措施:
反射和泛型结合使用可以创建更加灵活和通用的代码。例如,可以使用反射来创建泛型类的实例,或者调用泛型方法。
public class GenericClass<T> {
private T value;
public GenericClass(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
public class Main {
public static void main(String[] args) throws Exception {
// 使用反射创建泛型类的实例
Class<?> clazz = Class.forName("com.example.GenericClass");
Constructor<?> constructor = clazz.getConstructor(Object.class);
GenericClass<String> obj = (GenericClass<String>) constructor.newInstance("Hello");
// 获取泛型类型
Field field = clazz.getDeclaredField("value");
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
for (Type typeArgument : typeArguments) {
System.out.println("Generic type: " + typeArgument.getTypeName());
}
}
System.out.println("Value: " + obj.getValue());
}
}在这个例子中,我们使用反射创建了一个GenericClass<String>的实例,并获取了泛型类型的信息。
Class.forName()的实现原理Class.forName()方法是反射中最常用的方法之一。它的作用是根据类的全限定名加载类。那么,它的实现原理是什么呢?
Class.forName()方法的实现依赖于ClassLoader。ClassLoader是Java中负责加载类的组件。当调用Class.forName()方法时,它会委托给ClassLoader来加载类。
ClassLoader的加载过程如下:
ClassLoader首先会检查该类是否已经被加载。如果已经被加载,则直接返回该类的Class对象。ClassLoader会将加载任务委托给父类加载器。这个过程会一直递归到顶层的Bootstrap ClassLoader。ClassLoader会尝试自己加载该类。它会从指定的classpath中查找该类的.class文件,并将其加载到内存中。ClassLoader会调用defineClass()方法来定义该类。defineClass()方法会将.class文件中的字节码转换为Class对象。总的来说,Class.forName()方法的实现原理就是委托给ClassLoader来加载类。ClassLoader会按照一定的顺序查找和加载类,并将加载后的类定义为Class对象。
反射是Java语言的一项强大特性,它可以让你在运行时动态地操作类和对象。但是,反射也有一些缺点,例如性能开销和安全问题。因此,在使用反射时需要谨慎,并采取相应的措施来避免这些问题。
以上就是Java 反射机制高级应用与源码分析详解 (全网最透彻教程)的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号