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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
Instances of the class Class represent classes and interfaces in a running Java application.
Class has no public constructor. Instead Class objects are constructed automatically
by the Java Virtual Machine as classes are loaded and by calls to
the defineClass method in the class loader.
**/
public final class Class<T> implements java.io.Serializable,
GenericDeclaration, Type, AnnotatedElement {
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
}

Class 的构造函数是私有的,由 JVM 创建。

可以通过如下方式获取 Class 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Object 中的方法
Class<? extends String> stringClass = "".getClass();

Class<String> stringClass = String.class;

//Class 中的静态方法
Class<?> stringClass = Class.forName("java.lang.String");

// 基本数据类型通过 TYPE 属性,也是调用 Class 中的 Native 方法
Byte.TYPE Float.TYPE Boolean.TYPE

public static final Class<Byte> TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");

Class 中常用方法

1. getSuperclass():

返回类的父类或 java.lang.Object

1
2
3
4
5
/**
Returns the Class representing the superclass of the entity (class,
interface, primitive type or void) represented by this Class.
**/
public native Class<? super T> getSuperclass();

2. getClasses():

返回一个类中 public 的内部类,接口或枚举类。包括从父类继承的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

/**
Returns an array containing Class objects representing all the public classes
and interfaces that are members of the class represented by this Class object.
**/
public Class<?>[] getClasses() {
//检查是否是 public 的
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);

List<Class<?>> list = new ArrayList<>();
Class<?> currentClass = Class.this;
//循环获取当前类中 public 的类成员
while (currentClass != null) {
Class<?>[] members = currentClass.getDeclaredClasses();
for (int i = 0; i < members.length; i++) {
if (Modifier.isPublic(members[i].getModifiers())) {
list.add(members[i]);
}
}
currentClass = currentClass.getSuperclass();
}
return list.toArray(new Class<?>[0]);
}

3. getDeclaredClasses():

返回一个类中所有的内部类,接口或枚举类。不包括从父类继承的

1
2
3
4
5
6
7
8
9
10
/**
Returns an array of Class objects reflecting all the classes and interfaces
declared as members of the class represented by this Class object.
**/
public Class<?>[] getDeclaredClasses() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false);
return getDeclaredClasses0();
}

private native Class<?>[] getDeclaredClasses0();

4. getInterfaces():

返回类实现的接口或接口继承的接口的 Class 数组,数组顺序按声明时的顺序排列。

Method 方法类型

1
2
3
4
5
6
7
/*
A Method provides information about, and access to,
a single method on a class or interface.
The reflected method may be a class method or an instance method (including
an abstract method).
*/
public final class Method extends Executable {}

invoke 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Method.java
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; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}

private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}

return tmp;
}

invoke() 方法通过 MethodAccessor 调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ReflectionFactory.java
public MethodAccessor newMethodAccessor(Method method) {
checkInitted();

if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
return new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
} else {
NativeMethodAccessorImpl acc =
new NativeMethodAccessorImpl(method);
DelegatingMethodAccessorImpl res =
new DelegatingMethodAccessorImpl(acc);
acc.setParent(res);
return res;
}
}

MethodAccessor 是一个接口,具体实现类是 DelegatingMethodAccessorImplNativeMethodAccessorImpl.
NativeMethodAccessorImpl 通过本地方法实现反射调用;
DelegatingMethodAccessorImpl 通过委派模式调用。
他们两在源码中其实是委派关系,在第一次调用反射的时候,会调用委派实现,然后再将请求传到本地方法实现,最后再传给目标方法使用。

Field 成员类型

1
2
3
4
5
6
/*
A Field provides information about, and dynamic access to,
a single field of a class or an interface.
The reflected field may be a class (static) field or an instance field.
*/
public final class Field extends AccessibleObject implements Member {}

getDeclaredMethod()getDeclaredMethods() 包含当前类中所有的方法,不包含从父类中继承的。
getMethod()getMethods() 只包含 public 方法,包含从父类继承的方法。

Constructor 构造器类型

1
2
3
4
5
/*
Constructor provides information about, and access to,
a single constructor for a class.
*/
public final class Constructor<T> extends Executable {}

java_reflect_filed_method_constructor

FAQ

1: 反射可以修改 final 类型成员变量吗?

反射可以修改 staticfinal 修饰的变量;修改 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
    15
    java.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] 反射性能开销原理及优化