Java基础-反射

很多框架都使用了反射 Java的反射机制让类毫无隐私可言。

基本使用

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
public class Apple {

private int price;

public int getPrice() {
return price;
}

public void setPrice(int price) {
this.price = price;
}

public static void main(String[] args) throws Exception{
//正常的调用
Apple apple = new Apple();
apple.setPrice(5);
System.out.println("Apple Price:" + apple.getPrice());
//使用反射调用
Class clz = Class.forName("com.chenshuyi.api.Apple");
Method setPriceMethod = clz.getMethod("setPrice", int.class);
Constructor appleConstructor = clz.getConstructor();
Object appleObj = appleConstructor.newInstance();
setPriceMethod.invoke(appleObj, 14);
Method getPriceMethod = clz.getMethod("getPrice");
System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
}
}

反射调用方法的步骤

1
2
3
4
5
6
7
8
9
10
// 1.获取类的 Class 对象实例
Class clz = Class.forName("com.zhenai.api.Apple");
// 2.根据 Class 对象实例获取 Constructor 对象
Constructor appleConstructor = clz.getConstructor();
// 3.使用 Constructor 对象的 newInstance 方法获取反射类对象
Object appleObj = appleConstructor.newInstance();
// 4.获取方法的 Method 对象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
// 5.利用 invoke 方法调用方法
setPriceMethod.invoke(appleObj, 14);

常用api

  • 获取Class对象
1
Class clz = Class.forName("全限定类名");
1
Class clz = String.class;
1
2
3
// 类对象的getClass()
String str = "123";
Class clz = str.getClass();
  • 反射创建对象
1
2
// 通过Class创建对象只能选择默认的无参构造函数 
Apple apple = (Apple) clz.newInstance();
1
2
Constructor c = clz.getConstructor();
Apple apple = (Apple) c.newInstance();
1
2
3
// 通过Constructor创建对象可以选择不同构造函数
Constructor c = clz.getConstructor(String.class, int.class);
Apple apple = (Apple) c.newInstance("红富士", 15);
  • 获取类的属性与方法
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
32
33
34
35
36
37
package cn.deepblog.反射;

public class Apple {

private String name;

public int price;

protected String color;

int size;

public Apple() {
}

public Apple(String name, int price, String color, int size) {
this.name = name;
this.price = price;
this.color = color;
this.size = size;
}

@Override
public String toString() {
return "Apple{" +
"name='" + name + '\'' +
", price=" + price +
", color='" + color + '\'' +
", size=" + size +
'}';
}

private String reply(){

return "private method";
}
}
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package cn.deepblog.反射;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Reflecttest {

public static void main(String[] args) {

try {
Class clz = Class.forName("cn.deepblog.反射.Apple");

//返回public字段
Field[] publicFields = clz.getFields();

//返回全部字段
Field[] allFields = clz.getDeclaredFields();

//返回所有public方法 **包括继承的**
Method[] publicMethods = clz.getMethods();

//返回所有类中方法 **但不包括继承的方法**
Method[] allMethods = clz.getDeclaredMethods();

System.out.println("-------publicFields--------");
for(Field f : publicFields){
System.out.println(f.getName());
}

System.out.println("---------allFields------------");
for(Field f: allFields){
System.out.println(f.getName());
}

System.out.println("-------publicMethods----------");
for(Method m : publicMethods){
System.out.println(m.getName());
}

System.out.println("----------allMethods-----------");
for(Method m: allMethods){
System.out.println(m.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

控制台输出:
-------publicFields--------
price
---------allFields------------
name
price
color
size
-------publicMethods----------
toString
wait
wait
wait
equals
hashCode
getClass
notify
notifyAll
----------allMethods-----------
toString
reply

反射源码解析

反射中最最终的就是 Method 类的 invoke 方法。

进入Method.invoke() 其调用的其实是MethodAccessor.invoke()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@CallerSensitive
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);
<--
}

MethodAccessor其实是个接口

1
2
3
public interface MethodAccessor {
Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException;
}

其有三个具体实现类

  • DelegatingMethodAccessorImpl(代理方法权限器实现类)
  • MethodAccessorImpl
  • NativeMethodAccessorImpl

追踪acquireMethodAccessor

1
ma = acquireMethodAccessor();

发现是reflectionFactory制造了一个MethodAccessor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

继续追踪reflectionFactory.newMethodAccessor()

1
2
3
4
5
6
7
8
9
10
11
12
13
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;
<--
}
}

在 ReflectionFactory 类的 newMethodAccessor 方法里,我们可以看到首先是生成了一个 NativeMethodAccessorImpl 对象,再这个对象作为参数调用 DelegatingMethodAccessorImpl 类的构造方法。

这里的实现是使用了代理模式,将 NativeMethodAccessorImpl 对象交给 DelegatingMethodAccessorImpl (代理方法权限器实现类)对象代理。我们查看 DelegatingMethodAccessorImpl 类的构造方法可以知道,其实是将 NativeMethodAccessorImpl 对象赋值给 DelegatingMethodAccessorImpl 类的 delegate 属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}
}

进入DelegatingMethodAccessorImpl发现其invoke()就是调用了其属性delegate对应MethodAccessorImpl类的invoke() 所以这里调用的还是NativeMethodAccessorImpl.invoke()

NativeMethodAccessorImpl.invoke()会对调用次数numInvocations进行统计 其会判断调用次数是否超过阀值ReflectionFactory.inflationThreshold()。如果超过该阀值,那么就会生成另一个MethodAccessor 对象,并将原来 DelegatingMethodAccessorImpl 对象中的 delegate 属性指向最新的 MethodAccessor 对象。

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
32
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
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);
}

初次加载字节码实现反射,使用 Method.invoke() 和 Constructor.newInstance() 加载花费的时间是使用原生代码加载花费时间的 3 - 4 倍。这使得那些频繁使用反射的应用需要花费更长的启动时间。

实际的 MethodAccessor 实现有两个版本,一个是 Native 版本,一个是 Java 版本。

Native 版本一开始启动快,但是随着运行时间边长,速度变慢。Java 版本一开始加载慢,但是随着运行时间边长,速度变快。正是因为两种存在这些问题,所以第一次加载的时候我们会发现使用的是 NativeMethodAccessorImpl 的实现,而当反射调用次数超过 15 次之后,则使用 MethodAccessorGenerator 生成的 MethodAccessorImpl 对象去实现反射。而做不同MethodAccessor对象代理的正是DelegatingMethodAccessorImpl。

mdSynA.png

参考阅读

Donate here.