Java 反射
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.
JAVA 反射机制是在运行时对于任意一个类都能够知道这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个方法。这种动态的获取信息以及动态的调用对象方法的功能称为 java 语言的反射机制。
Class 类类型
1 | /** |
Class 的构造函数是私有的,由 JVM 创建。
可以通过如下方式获取 Class 对象:
1 | // Object 中的方法 |
Class 中常用方法
1. getSuperclass():
返回类的父类或 java.lang.Object。
1 | /** |
2. getClasses():
返回一个类中 public 的内部类,接口或枚举类。包括从父类继承的。
1 |
|
3. getDeclaredClasses():
返回一个类中所有的内部类,接口或枚举类。不包括从父类继承的。
1 | /** |
4. getInterfaces():
返回类实现的接口或接口继承的接口的 Class 数组,数组顺序按声明时的顺序排列。
Method 方法类型
1 | /* |
invoke 方法
1 | // Method.java |
invoke() 方法通过 MethodAccessor 调用。
1 | // ReflectionFactory.java |
MethodAccessor 是一个接口,具体实现类是 DelegatingMethodAccessorImpl 和 NativeMethodAccessorImpl.
NativeMethodAccessorImpl 通过本地方法实现反射调用;
DelegatingMethodAccessorImpl 通过委派模式调用。
他们两在源码中其实是委派关系,在第一次调用反射的时候,会调用委派实现,然后再将请求传到本地方法实现,最后再传给目标方法使用。
Field 成员类型
1 | /* |
getDeclaredMethod() 和 getDeclaredMethods() 包含当前类中所有的方法,不包含从父类中继承的。
而 getMethod() 和 getMethods() 只包含 public 方法,包含从父类继承的方法。
Constructor 构造器类型
1 | /* |

FAQ
1: 反射可以修改 final 类型成员变量吗?
反射可以修改 static 或 final 修饰的变量;修改 static final 变量会抛出 IllegalAccessException 异常。
String 及基本数据类型的 final 变量可以被修改,只是无法通过原对象获取到修改后的值。可以通过
Field.get(Object)方法获取修改后的值;原因是 JVM 存在内联优化,如 user.name 编译时直接替换为字符串常量 “Hello”;基本数据类型的引用类型的 final 变量能被修改,可以通过原对象的直接引用(如 user.name) 或 Field.get(Object obj) 方法获取修改后的值;
static final修饰的变量无法通过反射修改。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15java.lang.IllegalAccessException: Can not set static final xxxx
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:76)
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:80)
at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
at java.lang.reflect.Field.set(Field.java:764)
// sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.java
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException {
if (isReadOnly) {
// 调用父类方法,抛出 IllegalAccessException()
throw FinalFieldIllegalAccessException(value);
}
// ...
}
2. 反射为什么耗时?
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
由于反射涉及动态解析的类型,导致无法执行某些 Java 虚拟机优化。因此,反射操作的性能比它们的非反射操作要慢,并且应该避免在频繁调用的代码中使用反射。
参考
[1] The Reflection API
[2] ReflectASM - a very small Java library that provides high performance reflection by using code generation
[3] Joor
[4] ASM - an all purpose Java bytecode manipulation and analysis framework.
[5] 反射性能开销原理及优化