ReflectionData属性详解

a, 为了提高反射的性能,缓存显然是必须的。 class类内部提供了一个ReflectionData内部类用来存放反射数据的缓存,并声明了一个reflectionData域 ,由于稍后进行按需延迟加载并缓存,所以这个域并没有指向一个实例化的ReflectionData对象。
在Class类的代码中可以看出来:
private static void checkInitted() {
if ( initted ) return ;
AccessController. doPrivileged ( new PrivilegedAction<Void>() {
public Void run() {
if (System. out == null ) {
// java.lang.System not yet fully initialized
return null ;
}
// Doesn't use Boolean.getBoolean to avoid class init.
String val =
System. getProperty ( "sun.reflect.noCaches" );
if (val != null && val.equals( "true" )) {
useCaches = false ;
}
initted = true ;
return null ;
}
});
}
lass类内部有一个useCaches静态变量来标记是否使用缓存,这个值可以通过外部配置项sun.reflect.noCaches进行开关。



b. 对于这个 ReflectionData 的用法可以看Class类中获取类的构造函数这个方法来看
// publicOnly指示是否只获取public的构造函数,我们常用的getConstructors方法是只返回public的构造函数,而 getDeclaredConstructors返回的是所有构造函数,由于java的构造函数不会继承,所以这里不包含父类的构造函数。
private Constructor< T >[] privateGetDeclaredConstructors( boolean publicOnly) {
checkInitted ();
Constructor< T >[] res;
//这里缓存中读取reflectionData,如果还没有缓存,则创建一个reflectionData并设置到缓存。但是注意这个ReflectionData
//可能只是个空对象,里面并没有任何数据。
ReflectionData< T > rd = reflectionData(); -> 该方法比较重要在下文中c中有详细解释
if (rd != null ) {
res = publicOnly ? rd. publicConstructors : rd. declaredConstructors ;
if (res != null ) return res; //检查缓存中是否有数据 有的话直接返回
}
// No cached value available; request value from VM
if (isInterface()) {
@SuppressWarnings ( "unchecked" )
Constructor< T >[] temporaryRes = (Constructor< T >[]) new Constructor<?>[ 0 ];
res = temporaryRes; //接口没有构造函数
} else {
res = getDeclaredConstructors0(publicOnly); //native方法,从jvm中获取
}
//如果代码执行到了这里,说明需要更新缓存了,将之前从jvm中请求到的数据放置到缓存中。
if (rd != null ) {
if (publicOnly) {
rd. publicConstructors = res;
} else {
rd. declaredConstructors = res;
}
}
return res;
}
c. 比较重要的是reflectionData()这个调用。这个方法主要是用于延迟创建并缓存ReflectionData对象,注意是对象,里面并没有保存反射数据,这些数据只有在第一次执行相应的反射操作后才会被填充。
// Lazily create and cache ReflectionData
private ReflectionData< T > reflectionData() {
SoftReference <ReflectionData< T >> reflectionData = this . reflectionData ;
int classRedefinedCount = this . classRedefinedCount ;
ReflectionData< T > rd;
//检查缓存是否有效,如果有效,从缓存中直接返回reflectionData。
if ( useCaches &&
reflectionData != null &&
(rd = reflectionData.get()) != null &&
rd. redefinedCount == classRedefinedCount) {
return rd;
}
// else no SoftReference or cleared SoftReference or stale ReflectionData
// -> create and replace new instance
/ / 无法使用到缓存,创建新的reflectionData
return newReflectionData(reflectionData, classRedefinedCount);
}
对于这个SoftReference有必要解释一下,这个被称作为软引用: -> 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
example: SoftReference ref = new SoftReference( new MyDate());
-> MyDate date = new MyDate();
// 由JVM决定运行
If(JVM.内存不足()) {
date = null;
System.gc();
}

d: 继续追查newReflectionData()这个方法
private ReflectionData< T > newReflectionData(SoftReference<ReflectionData< T >> oldReflectionData, int classRedefinedCount) {
if (! useCaches ) return null ;
// 这里使用cas模式更新reflectionData,主要是考虑多线程并发更新的问题,可能有另外一个线程已经更新了reflectionData,并且设置了有效的缓存数据,如果这里再次更新就把缓存数据覆盖了。
while ( true ) {
ReflectionData< T > rd = new ReflectionData<>(classRedefinedCount);
// try to CAS it... cas是 compare and swap 比较并且替换的意思, java.util.concurrent包中借助CAS 实现了区别于synchronouse同步锁的一种乐观锁。
if (Atomic. casReflectionData ( this , oldReflectionData, new SoftReference<>(rd))) {
return rd; // cas成功,那么我们swap的这个新对象是有效的。
}
// else retry 重新读取oldReflectionData,为下次重试cas做准备。
oldReflectionData = this . reflectionData ;
classRedefinedCount = this . classRedefinedCount ;

//先判断这个oldReflectionData是否有效。如果是无效的数据,需要去重试cas一个新的ReflectionData了。
if (oldReflectionData != null &&
(rd = oldReflectionData.get()) != null &&
rd. redefinedCount == classRedefinedCount) {
return rd;
}
}
}
另外cas就不追究了在多线程的那个地方再深入研究.
上面的几个代码片段是反射获取一个类的构造函数的主要方法调用。主要流程就是先从class内部的reflectionData缓存中读取数据,如果没有缓存数据,那么就从jvm中去请求数据,然后设置到缓存中,供下次使用。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值