在上篇 Java 反射机制(一) 介绍了一些 Java
反射相关的经常使用 API ,在知道了如何去使用反射以后,做为一个合格的工程师,下一步确定是要去了解它的如何实现的,咱们今天就来看看在 JDK
源码中是如何去实现反射的(PS:如下源码分析基于 JDK1.8
)。html
Field
类的 set
方法是在运行时用来动态修改一个类的属性的值,进入到 Field
类的 set
方法的源码以下:java
public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException {
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
getFieldAccessor(obj).set(obj, value);
}
复制代码
首先根据 override
判断是否须要检查字段的访问权限,而后经过 getFieldAccessor
方法得到一个 FieldAccessor
字段访问者对象,最后调用的是 FieldAccessor
类的 set
方法进行下一步操做的,FieldAccessor
是一个接口,定义了对字段的一些操做,该接口有以下一些实现类:缓存
要看 set
到底调用的是哪一个实现类的方法,那么咱们须要看看 getFieldAccessor()
返回的是哪一个类的对象,下面是 getFieldAccessor
方法的源码实现:安全
// security check is done before calling this method
private FieldAccessor getFieldAccessor(Object obj) throws IllegalAccessException {
boolean ov = override;
FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
return (a != null) ? a : acquireFieldAccessor(ov);
}
复制代码
这里先经过 override
来获取不一样的缓存的 FieldAccessor
,其中 overrideFieldAccessor
表明本类覆盖父类的字段访问者对象缓存,fieldAccessor
是本类的字段访问器对象缓存。若是缓存存在的话就直接复用以前的对象,不然就调用 Field
类的 acquireFieldAccessor
方法获取。咱们进入到 acquireFieldAccessor
方法中看看,方法源码以下:ide
private FieldAccessor acquireFieldAccessor(boolean overrideFinalCheck) {
// First check to see if one has been created yet, and take it
// if so
FieldAccessor tmp = null;
if (root != null) tmp = root.getFieldAccessor(overrideFinalCheck);
if (tmp != null) {
if (overrideFinalCheck)
overrideFieldAccessor = tmp;
else
fieldAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newFieldAccessor(this, overrideFinalCheck);
setFieldAccessor(tmp, overrideFinalCheck);
}
return tmp;
}
复制代码
从 acquireFieldAccessor
的源码中咱们能够看到,先判断是否已存在 FieldAccessor
对象,若是存在的话那么就会复用以前的 FieldAccessor
对象,不然就使用 reflectionFactory
工厂的 newFieldAccessor
方法生成一个新的 FieldAccessor
对象出来。因此咱们就要进到 newFieldAccessor
方法里面看看是如何生成的,方法源码以下:源码分析
public FieldAccessor newFieldAccessor(Field var1, boolean var2) {
checkInitted();
return UnsafeFieldAccessorFactory.newFieldAccessor(var1, var2);
}
复制代码
从 newFieldAccessor
方法代码能够得知,在方法里面是经过 UnsafeFieldAccessorFactory
类的 static
方法 newFieldAccessor
来生产 FieldAccessor
的,那么咱们继续进入到 UnsafeFieldAccessorFactory
类的 newFieldAccessor
方法里面看看,方法源码以下:post
static FieldAccessor newFieldAccessor(Field var0, boolean var1) {
Class var2 = var0.getType();
boolean var3 = Modifier.isStatic(var0.getModifiers());
boolean var4 = Modifier.isFinal(var0.getModifiers());
boolean var5 = Modifier.isVolatile(var0.getModifiers());
boolean var6 = var4 || var5;
boolean var7 = var4 && (var3 || !var1);
if (var3) {
UnsafeFieldAccessorImpl.unsafe.ensureClassInitialized(var0.getDeclaringClass());
if (!var6) {
if (var2 == Boolean.TYPE) {
return new UnsafeStaticBooleanFieldAccessorImpl(var0);
} else if (var2 == Byte.TYPE) {
return new UnsafeStaticByteFieldAccessorImpl(var0);
} else if (var2 == Short.TYPE) {
return new UnsafeStaticShortFieldAccessorImpl(var0);
} else if (var2 == Character.TYPE) {
return new UnsafeStaticCharacterFieldAccessorImpl(var0);
} else if (var2 == Integer.TYPE) {
return new UnsafeStaticIntegerFieldAccessorImpl(var0);
} else if (var2 == Long.TYPE) {
return new UnsafeStaticLongFieldAccessorImpl(var0);
} else if (var2 == Float.TYPE) {
return new UnsafeStaticFloatFieldAccessorImpl(var0);
} else {
return (FieldAccessor)(var2 == Double.TYPE ? new UnsafeStaticDoubleFieldAccessorImpl(var0) : new UnsafeStaticObjectFieldAccessorImpl(var0));
}
}
// 剩下的部分省略...
}
}
复制代码
从以上 UnsafeFieldAccessorFactory
类的 newFieldAccessor
方法代码能够看出,方法里面经过类的字段修饰符类型和字段的类类型共同决定返回的 FieldAccessor
实现类,这里要注意一下方法里面这几个变量的含义:性能
static
关键字修饰的属性。final
关键字修饰的属性。valatile
关键字修饰的属性。valatile
关键字或者 final
关键字修饰的属性。final
关键字修饰的属性或者 static
关键字修饰而且不能覆盖(override = false
)的属性举一个例子,假设在一个类中的字段声明为 public static String name
,那么返回的字段访问器为 UnsafeStaticCharacterFieldAccessorImpl
,咱们看看这个类的 set
方法是如何实现的,方法源码以下:ui
public void set(Object var1, Object var2) throws IllegalArgumentException, IllegalAccessException {
if (this.isFinal) {
this.throwFinalFieldIllegalAccessException(var2);
}
if (var2 == null) {
this.throwSetIllegalArgumentException(var2);
}
if (var2 instanceof Character) {
unsafe.putChar(this.base, this.fieldOffset, (Character)var2);
} else {
this.throwSetIllegalArgumentException(var2);
}
}
复制代码
从上面方法的代码得知,方法最终仍是经过 Unsafe
类的 native
方法 putChar(Object var1, long var2, char var4)
来实现的,有关 Unsafe
类的介绍请看这篇文章(Java魔法类:Unsafe应用解析)。this
Method
类的 invoke
方法用来在运行时动态调用对象的方法,咱们进入到 Method
类的 invoke
方法中看看在 JDK
中究竟是怎么作的,方法源码以下:
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);
}
复制代码
从以上方法代码咱们能够看到,和上文说的的 Field
类同样,首先也是先根据 override
进行了一些权限检查,最后调用的是 MethodAccessor
的 invoke
方法进行处理,这个方法访问器 MethodAccessor
是一个接口,它只有一个操做方法调用的 invoke
方法,它有以下三个实现类:
要想知道 ma.invoke
具体调用的是哪一个类的方法,咱们须要看看方法 acquireMethodAccessor
返回的对象是哪一个,该方法的源码以下:
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;
}
复制代码
从以上方法 acquireMethodAccessor
的源码能够看出,首先会先先判断是否已经存在了对应的 MethodAccessor
对象,若是有就会复用这个对象,不然就调用工厂 reflectionFactory
的 newMethodAccessor
方法生成一个 MethodAccessor
对象出来。那么咱们就须要进入到方法 newMethodAccessor
中,方法源码以下:
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;
}
}
复制代码
从方法 newMethodAccessor
的代码能够看到,方法首先是使用 Method
对象做为入参生成了 NativeMethodAccessorImpl
对象,而后再使用 NativeMethodAccessorImpl
对象做为入参生成了 DelegatingMethodAccessorImpl
对象。这个使用了代理模式
,将 NativeMethodAccessorImpl
交给了 DelegatingMethodAccessorImpl
类进行了代理,进入到代理类 DelegatingMethodAccessorImpl
中能够看到:
从上面的红色方框能够看到,在类 DelegatingMethodAccessorImpl
的构造方法中将参数赋值给类中的 delegate
属性,全部上所说的 ma.invoke
最终会进入到 DelegatingMethodAccessorImpl
代理类的 invoke
,方法里调用的是 delegate
属性的 invoke
方法,该属性声明的类型为抽象类 MethodAccessorImpl
,它有以下两个实现类:
按照上文所说的,这里的 delegate
属性是 NativeMethodAccessorImpl
对象,那么就进入到 NativeMethodAccessorImpl
的 invoke
方法中,方法源码以下:
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);
}
复制代码
类 NativeMethodAccessorImpl
的 invoke
方法会先判断这次调用是否超过 ReflectionFactory.inflationThreshold()
方法返回的阈值(PS:默认的阈值大小为 15
),若是超过了该阈值,则使用方法访问生成器从新生成一个 MethodAccessorImpl
,并将 DelegatingMethodAccessorImpl
的 delegate
属性指向这个新生成的 MethodAccessorImpl
对象。从 Reflectionfactory
工厂类的一下注释:
能够得知 JVM
初次加载字节码实现反射的时候,使用 Method.invoke
和 Constructor.newInstance
方式加载所花费的时间是使用原生代码加载所花费的时间的 3 - 4 倍。这也就是咱们日常说为何频繁使用反射的应用须要花费更多的时间。JVM
做者们为了不这种花费较长的加载时间,咱们在第一次加载的时候重用了 JVM
的入口,以后切换到字节码实现的实现。 正如注释所述,在 MethodAccessor
接口的实现中,有两个不一样的版本,一个 Java
实现的,一个是 Native
实现的。Java
版本实现的版本在初始化的时须要比较多的时间,但长久来讲性能会更好一些;而 Native
版本则正好相反,在初始化时相对较快,可是在运行一段时间以后性能就不如 Java
版本的了。为了权衡两种版本的特性,sun
公司的 JDK
使用了 inflation
机制,让 Java
方法在被反射调用时,开头的几回调用使用 native
版,等反射调用次数超过阈值时则生成一个专用的 MethodAccessor
实现类,生成其中的 invoke
方法的字节码,之后对该 Java
方法的反射调用就会使用 Java
版。
本文主要介绍反射调用 set(Object obj, Object value)
方法和 invoke(Object obj, Object... args)
方法的底层实现,因为水平有限本人暂时尚未能力分析 JVM
的实现,这里只分析到最终 native
方法的调用。底层会依赖到 Unsafe
类来执行一些低级别、不安全操做的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提高 Java
运行效率、加强 Java
语言底层资源操做能力方面起到了很大的做用。对于属性反射的方法 setXXX
和 getXXX
的实现分别对应 Unsafe
类的 putXXX
和 getXXX
方法,也就是说彻底依赖 Unsafe
类中的 native
方法来实现的;对于方法反射的方法 invoke
底层调用的是 NativeMethodAccessorImpl
类的 invoke0
的 native
方法来实现的。对于反射构造器调用的实现,读者能够本身进入其源码进行分析,大致上和反射方法调用的实现相似。
参考文章