缺点
- 破坏封装:由于反射允许访问私有字段和私有方法,所以可能会破坏封装而导致安全问题。
- 性能开销:由于反射涉及到动态解析,因此无法执行 Java 虚拟机优化
应用场景
- 开发通用框架:像 Spring,为了保持通用性,通过配置文件来加载不同的对象,调用不同的方法。
- 动态代理:在面向切面编程中,需要拦截特定的方法,就会选择动态代理的方式,而动态代理的底层技术就是反射。
- 注解:注解本身只是起到一个标记符的作用,它需要利用发射机制,根据标记符去执行特定的行为。
| class CSer { |
| private String name; |
| private int mvp; |
| |
| |
| } |
| public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException { |
| CSer niko = new CSer(); |
| niko.setName("niko"); |
| System.out.println(niko.getName()); |
| |
| |
| Class clazz = Class.forName("test.ReflectTest.CSer"); |
| |
| Constructor constructor = clazz.getConstructor(); |
| |
| Object o = constructor.newInstance(); |
| |
| |
| Method setNameMethod = clazz.getMethod("setName", String.class); |
| Method getNameMethod = clazz.getMethod("getName"); |
| |
| setNameMethod.invoke(o, "glave"); |
| System.out.println(getNameMethod.invoke(o)); |
| } |
invoke源码
| boolean override; |
| |
| public Object invoke(Object obj, Object... args) |
| throws IllegalAccessException, IllegalArgumentException, |
| InvocationTargetException { |
| |
| if (!override) { |
| if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { |
| Class<?> caller = Reflection.getCallerClass(); |
| |
| checkAccess(caller, clazz, obj, modifiers); |
| } |
| } |
| |
| MethodAccessor ma = methodAccessor; |
| if (ma == null) { |
| |
| ma = acquireMethodAccessor(); |
| } |
| |
| return ma.invoke(obj, args); |
| } |
| |
| public interface MethodAccessor { |
| Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException; |
| } |
| private MethodAccessor acquireMethodAccessor() { |
| |
| |
| MethodAccessor tmp = null; |
| if (root != null) tmp = root.getMethodAccessor(); |
| if (tmp != null) { |
| |
| methodAccessor = tmp; |
| } else { |
| |
| |
| tmp = reflectionFactory.newMethodAccessor(this); |
| setMethodAccessor(tmp); |
| } |
| |
| return tmp; |
| } |
| public MethodAccessor newMethodAccessor(Method var1) { |
| checkInitted(); |
| if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) { |
| return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers()); |
| } else { |
| |
| NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1); |
| |
| |
| DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2); |
| var2.setParent(var3); |
| return var3; |
| } |
| } |
| class DelegatingMethodAccessorImpl extends MethodAccessorImpl { |
| private MethodAccessorImpl delegate; |
| |
| DelegatingMethodAccessorImpl(MethodAccessorImpl var1) { |
| this.setDelegate(var1); |
| } |
| |
| |
| public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException { |
| |
| return this.delegate.invoke(var1, var2); |
| } |
| |
| void setDelegate(MethodAccessorImpl var1) { |
| this.delegate = var1; |
| } |
| } |
| class NativeMethodAccessorImpl extends MethodAccessorImpl { |
| private final Method method; |
| private DelegatingMethodAccessorImpl parent; |
| private int numInvocations; |
| |
| NativeMethodAccessorImpl(Method var1) { |
| this.method = var1; |
| } |
| |
| public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException { |
| |
| if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) { |
| MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers()); |
| this.parent.setDelegate(var3); |
| } |
| |
| return invoke0(this.method, var1, var2); |
| } |
| |
| void setParent(DelegatingMethodAccessorImpl var1) { |
| this.parent = var1; |
| } |
| |
| private static native Object invoke0(Method var0, Object var1, Object[] var2); |
| } |
- 第一次加载的时候使用的是 NativeMethodAccessorImpl 的实现,而当反射调用次数超过 15 次之后(可以通过
-Dsun.reflect.inflationThreshold
参数类调整),则使用 MethodAccessorGenerator 生成的 MethodAccessorImpl 对象去实现反射。
获取反射类的Class对象

- Class.forName(),参数为反射类的完全限定名
| Class c1 = Class.forName("test.ReflectTest.CSer"); |
| |
| System.out.println(c1.getCanonicalName()); |
| |
| Class c2 = Class.forName("[D"); |
| |
| System.out.println(c2.getCanonicalName()); |
| |
| Class c3 = Class.forName("[[Ljava.lang.String;"); |
| |
| System.out.println(c3.getCanonicalName()); |
- 类名.class,只适合在编译前就知道操作的 Class
| Class c1 = CSer.class; |
| |
| System.out.println(c1.getCanonicalName()); |
| |
| Class c2 = String.class; |
| |
| System.out.println(c2.getCanonicalName()); |
| |
| Class c3 = int[][][].class; |
| |
| System.out.println(c3.getCanonicalName()); |
| CSer cSer = new CSer(); |
| Class clazz = cSer.getClass(); |
| |
| System.out.println(clazz.getCanonicalName()); |
创建反射类的对象
- 用 Class 对象的
newInstance()
方法
| Class clazz = CSer.class; |
| CSer cSer = (CSer) clazz.newInstance(); |
- 用 Constructor 对象的
newInstance()
方法
| Class clazz = CSer.class; |
| Constructor constructor = clazz.getConstructor(); |
| CSer cSer = (CSer) constructor.newInstance(); |
获取构造方法
getConstructor()
:返回反射类的特定 public 构造方法,可以传递参数,参数为构造方法参数对应 Class 对象;缺省的时候返回默认构造方法。
getDeclaredConstructor()
:返回反射类的特定构造方法,不限定于 public 的。
getConstructors()
:返回类的所有 public 构造方法。
getDeclaredConstructors()
:返回类的所有构造方法,不限定于 public 的。
| Constructor<?>[] declaredConstructors = String.class.getDeclaredConstructors(); |
| for (Constructor<?> declaredConstructor : declaredConstructors) { |
| System.out.println(declaredConstructor); |
| } |
获取字段和方法
- 同上,把关键字Constructor换成Field或Method
- 在访问私有方法和字段时,我们需要调用
setAccessible(true)
方法来允许访问
本文作者:n1ce2cv
本文链接:https://www.cnblogs.com/sprinining/p/18301796
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步