当前位置:网站首页>isAccessible()方法:使用反射技巧让你的性能提升数倍
isAccessible()方法:使用反射技巧让你的性能提升数倍
2022-07-29 05:21:00 【代码与思维】
今天这篇文章从源码的角度分析一下 isAccessible() 方法的作用,为什么将 Accessible 设置为 true 可以提升性能,在开始分析之前,我们先写一段代码。
- 声明一个普通类,里面有个
public方法getName()和private方法getAddress()
class Person {
public fun getName(): String {
return "I am DHL"
}
private fun getAddress(): String {
return "BJ"
}
}
- 通过反射获取
getName()和getAddress()方法,花 3 秒钟思考一下,下面的代码输出的结果
// public 方法
val method1 = Person::class.declaredFunctions.find { it.name == "getName" }
println("access = ${method1?.isAccessible}")
// private 方法
val method2 = Person::class.declaredFunctions.find { it.name == "getAddress" }
println("access = ${method2?.isAccessible}")
无论是调用 public getName() 方法还是调用 private getAddress() 方法,最后输出的结果都为 false,通过这个例子也间接说明了 isAccessible() 方法并不是用来表示访问权限的。
当我们通过反射调用 private 方法时,都需要执行 setAccessible() 方法设置为 true, 否者会抛出下面的异常。
java.lang.IllegalAccessException: can not access a member of class com.hi.dhl.demo.reflect.Person
如果通过反射调用 public 方法,不设置 Accessible 为 true,也可以正常调用,所以有很多小伙伴认为 isAccessible() 方法用来表示访问权限,其实这种理解是错误的。
我们一起来看一下源码是如何解释的,方法 isAccessible() 位于 AccessibleObject 类中。
public class AccessibleObject implements AnnotatedElement {
......
// NOTE: for security purposes, this field must not be visible
boolean override;
public boolean isAccessible() {
return override;
}
public void setAccessible(boolean flag) throws SecurityException {
......
}
......
}
AccessibleObject 是 Field 、 Method 、 Constructor 的父类,调用 isAccessible() 返回 override 的值,而字段 override 主要判断是否要进行安全检查。
字段 override 在 AccessibleObject 子类当中使用,所以我们一起来看一下它的子类 Method。
public Object invoke(Object obj, Object... args){
// 是否要进行安全检查
if (!override) {
// 进行快速验证是否是 Public 方法
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
// 返回调用这个方法的 Class
Class<?> caller = Reflection.getCallerClass();
// 做权限访问的校验,缓存调用这个方法的 Class,避免下次在做检查
checkAccess(caller, clazz, obj, modifiers);
}
}
......
return ma.invoke(obj, args);
}
字段 override 提供给子类去重写,它的值决定了是否要进行安全检查,如果要进行安全检查,则会执行 quickCheckMemberAccess() 快速验证是否是 Public 方法,避免调用 getCallerClass()。
- 如果是
Public方法,避免做安全检查,所以我们在代码中不调用setAccessible(true)方法,也不会抛出异常 - 如果不是
Public方法则会调用getCallerClass()获取调用这个方法的 Class,执行checkAccess()方法进行安全检查。
// it is necessary to perform somewhat expensive security checks.
// A more complicated security check cache is needed for Method and Field
// The cache can be either null (empty cache)
volatile Object securityCheckCache; // 缓存调用这个方法的 Class
void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers){
......
Object cache = securityCheckCache; // read volatile
if(cache == 调用这个方法的 Class){
return; // ACCESS IS OK
}
slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
......
}
void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers,Class<?> targetClass){
Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
Object cache = 调用这个方法的 Class
securityCheckCache = cache; // 缓存调用这个方法的 Class
}
源码中注释也说明了,如果要进行安全检查那么它的代价是非常昂贵的,所以用变量 securityCheckCache 缓存调用这个方法的 Class。如果下次使用相同的 Class,就不需要在做安全检查,但是这个缓存有个缺陷,如果换一个调用这个方法的 Class,需要再次做安全检查,并且会覆盖之前的缓存结果。
如果要在运行时修改属性或者调用某个方法时,都要进行安全检查,而安全检查是非常消耗资源的,所以 JDK 提供了一个 setAccessible() 方法,可以绕过安全检查,让开发者自己来决定是否要避开安全检查。
因为反射本身是非常慢的,如果能够避免安全检查,可以进一步提升性能,针对不同场景,分别测试了反射前后以及关闭安全检查的耗时。
| 正常调用 | 反射 | 反射优化后 | 反射优化后关掉安全检查 | |
|---|---|---|---|---|
| 创建对象 | 0.578 ms/op | 4.710 ms/op | 1.018 ms/op | 0.943 ms/op |
| 方法调用 | 0.422 ms/op | 10.533 ms/op | 0.844 ms/op | 0.687 ms/op |
| 属性调用 | 0.241 ms/op | 12.432 ms/op | 1.362 ms/op | 1.202 ms/op |
| 伴生对象 | 0.470 ms/op | 5.661 ms/op | 0.840 ms/op | 0.702 ms/op |
从测试结果可以看出来,执行 setAccessible() 方法,设置为 true 关掉安全检查之后,反射速度得到了进一步的提升,更接近于正常调用。
作者:程序员DHL
链接:https://juejin.cn/post/7121901090332737572
边栏推荐
- SSM integration
- C# 连接 SharepointOnline WebService
- 与张小姐的春夏秋冬(2)
- D3.JS 纵向关系图(加箭头,连接线文字描述)
- Gluster cluster management analysis
- "Shandong University mobile Internet development technology teaching website construction" project training log I
- day02 作业之文件权限
- IDEA中设置自动build-改动代码,不用重启工程,刷新页面即可
- 与张小姐的春夏秋冬(5)
- 以‘智’提‘质|金融影像平台解决方案
猜你喜欢

ReportingService WebService Form身份验证

Android Studio 实现登录注册-源代码 (连接MySql数据库)

华为2020校招笔试编程题 看这篇就够了(上)

“山东大学移动互联网开发技术教学网站建设”项目实训日志一

Super simple integration of HMS ml kit to realize parent control

微信小程序源码获取(附工具的下载)

Detailed steps of JDBC connection to database

Read and understand move2earn project - move

Simple optimization of interesting apps for deep learning (suitable for novices)

Bare metal cloud FASS high performance elastic block storage solution
随机推荐
MOVE PROTOCOL全球健康宣言,将健康运动进行到底
DCAT batch operation popup and parameter transfer
深度学习的趣味app简单优化(适合新手)
华为2020校招笔试编程题 看这篇就够了(下)
Thinkphp6 output QR code image format to solve the conflict with debug
mysql插入百万数据(使用函数和存储过程)
Ribbon学习笔记二
Dao race track is booming. What are the advantages of m-dao?
Performance comparison | FASS iSCSI vs nvme/tcp
Research and implementation of flash loan DAPP
The bear market is slow, and bit.store provides stable stacking products to help you get through the bull and bear market
中海油集团,桌面云&网盘存储系统应用案例
Idea using JDBC to connect mysql database personal detailed tutorial
从Starfish OS持续对SFO的通缩消耗,长远看SFO的价值
File permissions of day02 operation
与张小姐的春夏秋冬(5)
How to PR an open source composer project
win10+opencv3.2+vs2015配置
NIFI 改UTC时间为CST时间
学习、研究编程之道