java基础:反射
在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息,而这个类在编译过程中甚至是还未存在的。在运行的时候我们可以通过配置文件获取某个类的类名,然后使用反射机制构造这个类的对象,调用这个对象的方法,修改这个对象的成员变量。
1. 编译期和运行期
- 编译期:是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。
- 运行期:是把编译后的文件交给计算机执行,直到程序运行结束。运行期就把在磁盘中的代码放到内存中执行起来。
2. 反射机制
java执行编译的时候将java文件编译成字节码class文件,类加载器在类加载阶段将class文件加载到内存,并实例化一个java.lang.Class的对象。万事万物皆对象,Class被称为类对象,描述类在元数据空间的数据结构,包含类中定义的属性、方法、构造方法、注解、接口等信息。
当我们刚接触java语言的时候,我们最常写的代码应该就是初始化某个对象,然后调用该对象的方法。例如:
User user = new User();
user.getName();
当我们想在运行期才能指定具体对象的类型或调用的某个方法、属性时,普通的编码方式将无法实现需求。
Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息,而这个类在编译过程中甚至是还未存在的。在运行的时候我们可以通过配置文件获取某个类的类名,然后使用反射机制构造这个类的对象,调用这个对象的方法,修改这个对象的成员变量。
反射机制很重要的一点就是“运行时”,其使得我们可以在程序运行时加载、探索以及使用编译期间完全未知的 .class 文件。换句话说 Java 程序可以加载一个运行时才得知名称的 .class 文件,然后获悉其完整构造,并生成其对象实体、或对其 fields(变量)设值、或调用其 methods(方法)。一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
3. 原理解析
Java反射机制的原理主要是通过Class类来实现的。Class类是Java中反射机制的核心类,它可以在运行时动态地获取一个类的信息。使用Class.forName()方法获取Class对象,
Class.forName()方法接受一个字符串参数,该参数为完整类名,它将返回该类的Class对象。
Class<?> clazz = Class.forName("jvm.newInstance.NewInstanceDto");
//通过反射获取有参构造函数
//Class源码 public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);Constructor<?> c1 = clazz.getDeclaredConstructor()
//反射方式获取方法
//Class源码 public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
Method m1 = clazz.getDeclaredMethod()
//反射方式获取属性字段
//Class源码 public Field getDeclaredField(String name)Field f1 = clazz.getDeclaredField();
//反射方式调用方法结果
// Method 源码: public Object invoke(Object obj, Object... args)m1.invoke()
3.1. Constructor.newInstance 源代码解读
结论:当首次执行Constructor.newInstance()方法时,会通过reflectionFactory.newConstructorAccessor()在不同条件下选择合适的ConstructorAccessor
实现,并对返回的实现进行缓存,便于复用。
- 抽象类、
Class
类: 底层实现抛出InstantiationException 异常。 ConstructorAccessorImpl
的子类: 底层实现抛出InstantiationException 异常。- sun.reflect.noInflation 值设置为 ture: 通过字节码生成技术MethodAccessorGenerator.generateConstructor()(例如使用ASM库)生成一个新的
ConstructorAccessor
实现。实现类包含newInstance
方法,该方法直接调用目标待实例化对象的构造函数。可以在运行时高效地创建对象实例。 - sun.reflect.noInflation 值设置为 false: 返回 代理类
DelegatingConstructorAccessorImpl
。
而DelegatingConstructorAccessorImpl
(代理类)对象对NativeConstructorAccessorImpl
(Native 实现方式类)进行了代理,Constructor.newInstance()
在调用时候,实际执行的是NativeConstructorAccessorImpl.newInstance()
方法。
NativeConstructorAccessorImpl.newInstance()
方法在执行时,通过属性numInvocations
计数,当调用次数超过一定次数, 通过字节码生成技术MethodAccessorGenerator.generateConstructor()(例如使用ASM库)生成一个新的 ConstructorAccessor
实现。 NativeConstructorAccessorImpl 对象通过自身持有的parent 属性执行parent.setDelegate(acc)
操作,对DelegatingConstructorAccessorImpl
对象的代理对象进行切换,后续方法执行底层方式切换为新的 ConstructorAccessor
实现。
3.1.1. Constructor.newInstance
public T newInstance(Object ... initargs)throws InstantiationException, IllegalAccessException,IllegalArgumentException, InvocationTargetException{// 安全性权限校验if (!override) {// 快速检查成员访问权限if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {Class<?> caller = Reflection.getCallerClass();//检查访问权限checkAccess(caller, clazz, null, modifiers);}}//是否为枚举类型。不允许通过反射创建枚举对象,有助于保持枚举的完整性if ((clazz.getModifiers() & Modifier.ENUM) != 0)throw new IllegalArgumentException("Cannot reflectively create enum objects");ConstructorAccessor ca = constructorAccessor; // read volatileif (ca == null) {ca = acquireConstructorAccessor();}@SuppressWarnings("unchecked")T inst = (T) ca.newInstance(initargs);return inst;
}
//获取实现private ConstructorAccessor acquireConstructorAccessor() {// 第一步:检查是否已有实现。若有则返回,缓存机制。ConstructorAccessor tmp = null;if (root != null) tmp = root.getConstructorAccessor();if (tmp != null) {constructorAccessor = tmp;} else {// 没有则通过reflectionFactory生成tmp = reflectionFactory.newConstructorAccessor(this);setConstructorAccessor(tmp);}return tmp;
}
//缓存reflectionFactory生成的ConstructorAccessor实现。
void setConstructorAccessor(ConstructorAccessor accessor) {constructorAccessor = accessor;// Propagate upif (root != null) {root.setConstructorAccessor(accessor);}
}
第一次调用 Constructor.newInstance()
时候,会调用reflectionFactory.newConstructorAccessor()
创建一个新的ConstructorAccessor,并赋值给methodAccessor进行缓存。
3.1.2. reflectionFactory.newConstructorAccessor()
public ConstructorAccessor newConstructorAccessor(Constructor<?> c) {//1.检查初始化状态checkInitted();// 获取当前构造器所属的类。Class<?> declaringClass = c.getDeclaringClass();if (Modifier.isAbstract(declaringClass.getModifiers())) {//如果声明类是抽象,最终处理方式抛出InstantiationException异常,因为不能直接实例化抽象类return new InstantiationExceptionConstructorAccessorImpl(null);}if (declaringClass == Class.class) {//声明类是Class类本身,最终处理方式抛出InstantiationException异常,因为不能直接实例化Class类本身return new InstantiationExceptionConstructorAccessorImpl("Can not instantiate java.lang.Class");}//if (Reflection.isSubclassOf(declaringClass,ConstructorAccessorImpl.class)) {//处理ConstructorAccessorImpl 的子类实例化 避免循环引用问题。 return new BootstrapConstructorAccessorImpl(c);}//noInflation 用于控制反射方法访问器的生成策略,以平衡性能和资源消耗。//-通过设置系统属性 sun.reflect.noInflation,开发人员可以在特定情况下优化反射操作的性能。if (noInflation && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {// 生成java实现方式实现类return new MethodAccessorGenerator().generateConstructor(c.getDeclaringClass(),c.getParameterTypes(),c.getExceptionTypes(),c.getModifiers());} else {//生成代理类DelegatingConstructorAccessorImpl实现。NativeConstructorAccessorImpl acc =new NativeConstructorAccessorImpl(c);DelegatingConstructorAccessorImpl res =new DelegatingConstructorAccessorImpl(acc);acc.setParent(res);return res;}
}
reflectionFactory.newConstructorAccessor()
在不同条件下选择合适的ConstructorAccessor
实现,以确保能够高效、正确地通过反射创建对象实例:
- 抽象类、
Class
类: 返回InstantiationExceptionConstructorAccessorImpl
; ConstructorAccessorImpl
的子类: 返回BootstrapConstructorAccessorImpl
;- sun.reflect.noInflation 值设置为 ture: 通过字节码生成技术MethodAccessorGenerator.generateConstructor()(例如使用ASM库)生成一个新的
ConstructorAccessor
实现并返回。 - sun.reflect.noInflation 值设置为 false: 返回 代理类
DelegatingConstructorAccessorImpl
。代理类DelegatingConstructorAccessorImpl
与 Native 实现方式类NativeConstructorAccessorImpl
互相持有引用。
3.1.3. InstantiationExceptionConstructorAccessorImpl
class InstantiationExceptionConstructorAccessorImplextends ConstructorAccessorImpl {private final String message;InstantiationExceptionConstructorAccessorImpl(String message) {this.message = message;}public Object newInstance(Object[] args)throws InstantiationException,IllegalArgumentException,InvocationTargetException{if (message == null) {throw new InstantiationException();}throw new InstantiationException(message);}
}
调用newInstance 抛出new InstantiationException()异常,兼容特殊情况。
3.1.4. BootstrapConstructorAccessorImpl
class BootstrapConstructorAccessorImpl extends ConstructorAccessorImpl {private final Constructor<?> constructor;BootstrapConstructorAccessorImpl(Constructor<?> c) {this.constructor = c;}public Object newInstance(Object[] args) throws IllegalArgumentException, InvocationTargetException{try {return UnsafeFieldAccessorImpl.unsafe.allocateInstance(constructor.getDeclaringClass());} catch (InstantiationException e) {throw new InvocationTargetException(e);}}
}
底层调用 UnsafeFieldAccessorImpl.unsafe.allocateInstance(constructor.getDeclaringClass());
native 本地方法生成目标对象实例。
3.1.5. NativeConstructorAccessorImpl
class DelegatingConstructorAccessorImpl extends ConstructorAccessorImpl {private ConstructorAccessorImpl delegate;DelegatingConstructorAccessorImpl(ConstructorAccessorImpl delegate) {setDelegate(delegate);}public Object newInstance(Object[] args)throws InstantiationException,IllegalArgumentException,InvocationTargetException {return delegate.newInstance(args);}void setDelegate(ConstructorAccessorImpl delegate) {this.delegate = delegate;}
}
DelegatingConstructorAccessorImpl
持有NativeConstructorAccessorImpl
引用delegate
,并且自身方法invoke()
对NativeConstructorAccessorImpl.invoke()
进行了包装,底层执行的还是NativeConstructorAccessorImpl.invoke()。
3.1.6. DelegatingConstructorAccessorImpl
class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {private final Constructor<?> c;private DelegatingConstructorAccessorImpl parent;private int numInvocations;NativeConstructorAccessorImpl(Constructor<?> c) {this.c = c;}public Object newInstance(Object[] args) throws InstantiationException,IllegalArgumentException,InvocationTargetException{//1.1、numInvocations记录调用次数,//-当调用次数超过ReflectionFactory.inflationThreshold()设定的值且非匿名类,切换ConstructorAccessorImpl实例//1.2、ReflectUtil.isVMAnonymousClass():所属的类是否是虚拟机匿名类(vm-anonymous class)。//-如果是匿名类,不能生成字节码,因为匿名类没有名字,无法在生成的字节码中引用。if (++numInvocations > ReflectionFactory.inflationThreshold()&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {//1-1、使用 MethodAccessorGenerator 生成一个新的 ConstructorAccessor 实现。ConstructorAccessorImpl acc = (ConstructorAccessorImpl)new MethodAccessorGenerator().generateConstructor(c.getDeclaringClass(),c.getParameterTypes(),c.getExceptionTypes(),c.getModifiers());//1-2、将生成的 ConstructorAccessor 设置为 parent 的代理,后续调用执行新的 ConstructorAccessor 实现。parent.setDelegate(acc);}//2、执行本地方法。return newInstance0(c, args);}void setParent(DelegatingConstructorAccessorImpl parent) {this.parent = parent;}private static native Object newInstance0(Constructor<?> c, Object[] args)throws InstantiationException,IllegalArgumentException,InvocationTargetException;
}
NativeConstructorAccessorImpl
的主要作用是通过本地方法高效地创建对象实例。通过属性numInvocations
计数,当调用次数超过一定次数, 通过字节码生成技术MethodAccessorGenerator.generateConstructor()(例如使用ASM库)生成一个新的 ConstructorAccessor
实现。这个生成的实现是纯Java代码,但经过优化,可以在运行时高效地创建对象实例。 并且通过自身持有的parent 属性parent.setDelegate(acc)
,对DelegatingConstructorAccessorImpl
对象的代理对象进行切换。
3.1.7. NativeConstructorAccessorImpl 与MethodAccessorGenerator.generateConstructor()区别。
- 实现方式:
-
NativeConstructorAccessorImpl
: 使用本地方法(native method)来创建对象实例,由JVM实现。MethodAccessorGenerator.generateConstructor()
: 通过字节码生成技术动态生成一个纯Java的ConstructorAccessor
实现。
- 灵活性
-
NativeConstructorAccessorImpl
: 果构造器的签名发生变化,NativeConstructorAccessorImpl
无法动态调整,需要重新生成或选择其他实现。MethodAccessorGenerator.generateConstructor()
:可以根据具体的构造器参数和异常类型生成最合适的实现。这种灵活性使得它可以适应各种不同的构造器签名。
- 性能:
-
NativeConstructorAccessorImpl
: 通常在初始调用时性能较好,因为本地方法调用通常比纯Java代码快。频繁调用时开销较大,影响性能(方法查找和动态绑定)。MethodAccessorGenerator.generateConstructor()
: 会直接调用目标类的默认构造方法,避免了反射API的开销。初始生成时间较长,在频繁调用时性能更好。
- 适用场景:
-
NativeConstructorAccessorImpl
: 适用于初始调用和中等频率的调用。MethodAccessorGenerator.generateConstructor()
: 适用于高频率的调用,特别是当同一个构造器被频繁调用时。
3.2. Method.invoke 源代码解读
结论:当首次执行Method.invoke()时候,会调用reflectionFactory.newMethodAccessor(this)会根据sun.reflect.noInflation 配置情况, 选择MethodAccessor
具体实现类,并实现类进行缓存。
- noInflation 为 ture :返回使用字节码生成技术
MethodAccessorGenerator().generateMethod()
(如ASM库)动态生成的类。(生成的类实现了MethodAccessorImpl
接口,并包含一个invoke
方法,该方法直接调用目标方法,而不是通过反射API。) - noInflation false : 代理类DelegatingMethodAccessorImpl并返回 。代理类
DelegatingMethodAccessorImpl
与Native 类NativeMethodAccessorImpl
互相持有引用。
而DelegatingMethodAccessorImpl
对象 对NativeMethodAccessorImpl
对象进行了代理,Method.invoke()
在调用时候,实际执行的是NativeMethodAccessorImpl.invoke()
方法。
在执行NativeMethodAccessorImpl.invoke()
方法时候,通过numInvocations
属性对调用次数进行了计数;当调用次数超过设定次数后并且不是匿名类,则会进行新的MethodAccessorImpl
的创建,通过MethodAccessorGenerator.generateMethod
使用字节码生成技术(如ASM库)动态生成一个新的类。NativeMethodAccessorImpl 对象通过自身持有的parent 属性执行parent.setDelegate(acc)
操作,对DelegatingMethodAccessorImpl
对象的代理对象进行切换,后续方法执行底层方式切换为新的 NativeMethodAccessor
实现。
3.2.1. Method.invoke()
public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException{// 判定是否绕过 Java 的访问控制检查(setAccessible(true)),允许反射代码访问私有或受保护方法或属性if (!override) {//快速的方式来进行初步的权限检查if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {Class<?> caller = Reflection.getCallerClass();//执行更详细的权限验证checkAccess(caller, clazz, obj, modifiers);}}MethodAccessor ma = methodAccessor; if (ma == null) {// 这里会调用reflectionFactory.newMethodAccessor(this)创建一个新的MethodAccessor// 并赋值给methodAccessor,下次就不会进入到这里了// ma实际类型是DelegatingMethodAccessorImpl,代理对目标方法的调用ma = acquireMethodAccessor();}// 执行return ma.invoke(obj, args);
}
// 获取MethodAccessor实现
private MethodAccessor acquireMethodAccessor() {// 第一步:检查是否有已存在的 MethodAccessor 实例MethodAccessor tmp = null;if (root != null) tmp = root.getMethodAccessor();if (tmp != null) {methodAccessor = tmp;} else {// 第二步:如果没有已存在的 MethodAccessor 实例,通过reflectionFactory生成tmp = reflectionFactory.newMethodAccessor(this);setMethodAccessor(tmp);}return tmp;}
//缓存MethodAccessor实现
void setMethodAccessor(MethodAccessor accessor) {methodAccessor = accessor;if (root != null) {root.setMethodAccessor(accessor);}
}
初次 执行Method.invoke 执行时,reflectionFactory.newMethodAccessor(this)创建一个新的MethodAccessor,并赋值给methodAccessor进行缓存。
3.2.2. reflectionFactory.newMethodAccessor()
public MethodAccessor newMethodAccessor(Method method) {//初始化检查checkInitted();//noInflation 用于控制反射方法访问器的生成策略,以平衡性能和资源消耗。//-通过设置系统属性 sun.reflect.noInflation,开发人员可以在特定情况下优化反射操作的性能。if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {return new MethodAccessorGenerator().generateMethod(method.getDeclaringClass(),method.getName(),method.getParameterTypes(),method.getReturnType(),method.getExceptionTypes(),method.getModifiers());} else {// DelegatingMethodAccessorImpl对象代理 NativeMethodAccessorImpl对象。NativeMethodAccessorImpl acc =new NativeMethodAccessorImpl(method);DelegatingMethodAccessorImpl res =new DelegatingMethodAccessorImpl(acc);//NativeMethodAccessorImpl也持有了DelegatingMethodAccessorImpl的引用。acc.setParent(res);return res;}
}
reflectionFactory.newMethodAccessor()
方法根据sun.reflect.noInflation 配置使用, 选择使用哪种MethodAccessor
实现。
noInflation 为ture :返回使用字节码生成技术 MethodAccessorGenerator().generateMethod()
(如ASM库)动态生成的类。(生成的类实现了 MethodAccessorImpl
接口,并包含一个 invoke
方法,该方法直接调用目标方法,而不是通过反射API。)
noInflation 为false : 返回代理类DelegatingMethodAccessorImpl并返回 。代理类DelegatingMethodAccessorImpl
与Native 类 NativeMethodAccessorImpl
互相持有引用。
3.2.3. DelegatingMethodAccessorImpl
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {private MethodAccessorImpl delegate;DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {setDelegate(delegate);}public Object invoke(Object obj, Object[] args)throws IllegalArgumentException, InvocationTargetException{//标准代理模式:底层实现由持有的对象实现。return delegate.invoke(obj, args);}void setDelegate(MethodAccessorImpl delegate) {this.delegate = delegate;}
}
DelegatingMethodAccessorImpl
持有NativeMethodAccessorImpl
引用delegate
,并且自身方法invoke()
对NativeMethodAccessorImpl.invoke()
进行了包装(代理模式)。
3.2.4. NativeMethodAccessorImpl
class NativeMethodAccessorImpl extends MethodAccessorImpl {private final Method method;private DelegatingMethodAccessorImpl parent;private int numInvocations;NativeMethodAccessorImpl(Method method) {this.method = method;}public Object invoke(Object obj, Object[] args)throws IllegalArgumentException, InvocationTargetException{// numInvocations 调用次数计数//次数计数大于ReflectionFactory.inflationThreshold()并且不是匿名类切换为MethodAccessorGenerator().generateMethod();if (++numInvocations > ReflectionFactory.inflationThreshold()&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {MethodAccessorImpl acc = (MethodAccessorImpl)new MethodAccessorGenerator().generateMethod(method.getDeclaringClass(),method.getName(),method.getParameterTypes(),method.getReturnType(),method.getExceptionTypes(),method.getModifiers());parent.setDelegate(acc);}return invoke0(method, obj, args);}void setParent(DelegatingMethodAccessorImpl parent) {this.parent = parent;}private static native Object invoke0(Method m, Object obj, Object[] args);
}
reflectionFactory.newMethodAccessor()
返回的是DelegatingMethodAccessorImpl
对象,并且对DelegatingMethodAccessorImpl
对象进行缓存。而DelegatingMethodAccessorImpl
对NativeMethodAccessorImpl
进行了代理,Method.invoke()
在调用时候,实际执行的是NativeMethodAccessorImpl.invoke()
方法。
在执行NativeMethodAccessorImpl.invoke()
方法时候,通过numInvocations
属性对调用次数进行了计数;
当调用次数超过设定次数后并且不是匿名类,则会进行新的MethodAccessorImpl
的创建,通过MethodAccessorGenerator.generateMethod
使用字节码生成技术(如ASM库)动态生成一个新的类。NativeMethodAccessorImpl 对象通过自身持有的parent 属性执行parent.setDelegate(acc)
操作,对DelegatingMethodAccessorImpl
对象的代理对象进行切换,后续方法执行底层方式切换为新的 NativeMethodAccessor
实现。
4. 用途
4.1. 动态创建和访问对象
可以在运行时动态地创建对象,而不需要在编译时知道具体的类名。
- 示例:使用
Class.forName
和Constructor.newInstance
创建对象。
Class<?> clazz = Class.forName("jvm.newInstance.NewInstanceDto");// 反射获取对象方式方式1 : 通过反射获取无参构造函数 (无参构造函数必须public修饰,否则会抛出 IllegalAccessException)
Object o1 = clazz.newInstance();
// 反射获取对象方式2 : 通过反射获取有参构造函数
Constructor<?> c1 = clazz.getDeclaredConstructor(String.class);
// 绕过 Java 的访问控制检查,允许反射代码访问私有或受保护方法或属性
c1.setAccessible(true);
Object o2 = c1.newInstance("o2-1");
4.2. 动态访问字段:
可以在运行时动态地访问和修改对象的字段,即使这些字段是私有的。
- 示例:使用
Field
类访问和修改字段。
Class<?> clazz = Class.forName("jvm.newInstance.NewInstanceDto");
Object o1 = clazz.newInstance();
// 反射方式获取属性字段
Field f1 = clazz.getDeclaredField("id");
// 绕过 Java 的访问控制检查,允许反射代码访问私有或受保护方法或属性
f1.setAccessible(true);
// 重置值:
f1.set(o1, "o1-2");
4.3. 动态调用方法
可以在运行时动态地调用对象的方法,即使这些方法是私有的。
- 示例:使用
Method
类调用方法。
Class<?> clazz = Class.forName("jvm.newInstance.NewInstanceDto");
Object o1 = clazz.newInstance();
// 反射方式获取方法方式1
Method m1 = clazz.getDeclaredMethod("execute", String.class);
// 绕过 Java 的访问控制检查,允许反射代码访问私有或受保护方法或属性
m1.setAccessible(true);
m1.invoke(o1, "o1");
4.4. 获取类信息
可以在运行时获取类的详细信息,包括类名、父类、接口、注解等。
- 示例:获取类的名称和父类。
Class<?> clazz = Class.forName("jvm.newInstance.NewInstanceDto");
String className = clazz.getName();
Class<?> superClass = clazz.getSuperclass();
... ... ...
4.5. 动态代理
可以在运行时创建接口的代理类,实现AOP(面向切面编程)等功能。
- 示例:使用
Proxy
类创建动态代理。
InvocationHandler handler = new MyInvocationHandler();
NewInstanceDto proxy = (NewInstanceDto) Proxy.newProxyInstance(NewInstanceDto.class.getClassLoader(),new Class<?>[] { NewInstanceDto.class },handler
);
4.6. 注解处理
可以在运行时读取和处理类、方法、字段上的注解。
- 示例:读取类上的注解。
Class<?> clazz = Class.forName("jvm.newInstance.NewInstanceDto");;
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
4.7. 框架和库开发
多框架和库(如Spring、Hibernate、JUnit等)广泛使用反射来实现依赖注入、ORM、单元测试等功能。
- 示例:Spring框架使用反射实现依赖注注
4.8.插件系统
可以在运行时动态加载和卸载插件,实现模块化和可扩展的系统架构。
- 示例:动态加载插件。
File pluginDir = new File("plugins");
File[] pluginFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar"));for (File pluginFile : pluginFiles) {URL url = pluginFile.toURI().toURL();URLClassLoader classLoader = new URLClassLoader(new URL[] { url });Class<?> class = Class.forName("jvm.newInstance.NewInstance", true, classLoader);Object plugin = class.getDeclaredConstructor().newInstance()
}
5. 示例
public static void main(String[] args) throws Exception {// 获取class对象Class<?> clazz = Class.forName("jvm.newInstance.NewInstanceDto");// 反射获取对象方式方式1 : 通过反射获取无参构造函数 (无参构造函数必须public修饰,否则会抛出 IllegalAccessException)Object o1 = clazz.newInstance();// 反射获取对象方式2 : 通过反射获取有参构造函数Constructor<?> c1 = clazz.getDeclaredConstructor(String.class);// 绕过 Java 的访问控制检查,允许反射代码访问私有或受保护方法或属性c1.setAccessible(true);Object o2 = c1.newInstance("o2-1");// 反射方式获取方法方式1Method m1 = clazz.getDeclaredMethod("execute", String.class);// 绕过 Java 的访问控制检查,允许反射代码访问私有或受保护方法或属性m1.setAccessible(true);// 反射获取方法方式2:Method m2 = clazz.getDeclaredMethod("execute", String.class, int.class);// 绕过 Java 的访问控制检查,允许反射代码访问私有或受保护方法或属性m2.setAccessible(true);// 反射方式获取属性字段Field f1 = clazz.getDeclaredField("id");// 绕过 Java 的访问控制检查,允许反射代码访问私有或受保护方法或属性f1.setAccessible(true);// 调用方法结果:>>> >>> >>> execute info o1 this.id : nullm1.invoke(o1, "o1");// 重置值:id -> o1-2f1.set(o1, "o1-2");// 调用方法结果:>>> >>> >>> execute info o1 this.id : o1-2m1.invoke(o1, "o1");// 调用方法结果:>>> >>> >>> execute info 02 this.id : o2-1 key : 1m2.invoke(o2, "02", 1);// 重置值:id -> o2-2f1.set(o2, "o2-2");// 调用方法结果:>>> >>> >>> execute info 02 this.id : o2-1 key : 2m2.invoke(o2, "02", 2);}