了解jvm原理,
java基础栏目今天介绍超详细的JVM反射原理技术点总结哦。
反射定义
1、JAVA反射机制是在运行状态中
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为爪哇岛语言的反射机制。
反射提供的功能:
在运行时判断任意一个对象所属的类在运行时构造任意一个类的对象在运行时判断任意一个类所具有的成员变量和方法在运行时调用任意一个对象的方法(如果属性是private,正常情况下是不允许外界操作属性值,这里可以用Field类的setAccessible(true)方法,暂时打开操作的权限)
反射的使用场景
Java编码时知道类和对象的具体信息,此时直接对类和对象进行操作即可,无需反射如果编码时不知道类或者对象的具体信息,此时应该使用反射来实现
反射源码解析
举例API:
班级。forname( com。我的。反映测试”).新实例()复制代码
1. 反射获取类实例 Class.forName("xxx");
首先调用了java.lang.Class的静态方法,获取类信息!
注意:forName()反射获取类信息,并没有将实现留给了java,而是交给了虚拟机(Java虚拟机的缩写)去加载!
主要是先获取类加载器,然后调用当地的方法,获取信息,加载类则是回调入参类加载器进类加载!
@来电敏感
公共静态类?forName(字符串类名)
引发ClassNotFoundException {
//先通过反射,获取调用进来的类信息,从而获取当前的类加载器
班级?呼叫者=反射。getcallerclass();
//调用当地的方法进行获取班级信息
返回forName0(className,true,类加载器。get类加载器(caller),调用者);
}复制代码
2. java.lang.ClassLoader-----loadClass()
//Java。郎。类装入器
受保护阶层?装载类别(字符串名称,布尔解析)
引发ClassNotFoundException
{
//先获取锁
synchronized(getClassLoadingLock(name)){
//首先,检查该类是否已经加载
//如果已经加载了的话,就不用再加载了
班级?c=findLoadedClass(name);
if (c==null) {
长t0=系统。纳米时间();
尝试{
//双亲委托加载
如果(家长!=null) {
c=parent.loadClass(name,false);
}否则{
c=findBootstrapClassOrNull(name);
}
} catch(ClassNotFoundException e){
//如果找不到类,则引发ClassNotFoundException
//来自非空的父类加载器
}
//父类没有加载到时,再自己加载
if (c==null) {
//如果还是找不到,那么就按顺序调用查找类
//来查找类。
长t1=系统。纳米时间();
c=查找类(名称);
//这是定义类加载器;记录统计数据
星期日杂项性能计数器。getparentdelegationtime().添加时间(t1-t0);
星期日杂项性能计数器。getfindclasstime().addElapsedTimeFrom(t1);
星期日杂项性能计数器。getfindclass().increment();
}
}
如果(解决){
解决类(c);
}
返回c;
}
}
受保护对象getClassLoadingLock(字符串类名){
对象锁=这个
if (parallelLockMap!=null) {
//使用实现队列来保存锁
Object new lock=new Object();
lock=parallellockmap。菩提缺席(类名,新锁);
if (lock==null) {
lock=newLock
}
}
回车锁;
}
受保护的最终类?findLoadedClass(字符串名称){
如果(!checkName(name))
返回空
返回findloadedclass 0(名称);
}复制代码
3. newInstance()
新实例()其实相当于调用类的无参构造函数,主要做了三件事复制代码权限检测,如果不通过直接抛出异常;
查找无参构造器,并将其缓存起来;
调用具体方法的无参构造方法,生成实例并返回;
//首先肯定是Class.newInstance
@来电敏感
public T newInstance()
引发InstantiationException,IllegalAccessException
{
if (System.getSecurityManager()!=null) {
checkMemberAccess(成员PUBLIC,Reflection.getCallerClass(),false);
}
//注意:下面的代码在
//当前的爪哇内存模型。
//构造函数查找
//newInstance()其实相当于调用类的无参构造函数,所以,首先要找到其无参构造器
if (cachedConstructor==null) {
if (this==Class.class) {
//不允许调用班级的新实例()方法
抛出新的IllegalAccessException(
无法对 java.lang.Class 的类调用新实例()
);
}
尝试{
//获取无参构造器
班级?[]empty={ };
最终构造函数c=get构造函数0(空,成员。已声明);
//禁用构造函数的可访问性检查
//因为我们无论如何都要在这里进行安全检查
//(堆栈深度对于构造函数的是错误的
//安全检查工作)
Java。安全。门禁控制器。特权(
新Java。安全。privilegedactionvoid(){
公共无效运行(){
c。设置可访问性(true);
返回空
}
});
缓存的构造函数=c;
} catch(NoSuchMethodException e){
throw (InstantiationException)
新实例化异常(getName()).初始化原因(e);
}
}
构造函数tmp constructor=缓存的构造函数;
//安全检查(与java.lang.reflect.Constructor中相同)
int modifiers=tmp构造函数。get修饰符();
如果(!反思。快速检查成员访问(this,modifiers)) {
班级?呼叫者=反射。getcallerclass();
if (newInstanceCallerCache!=呼叫者){
反思。ensurememberaccess(调用者、this、null、修饰符);
newInstanceCallerCache=呼叫者
}
}
//运行构造函数
尝试{
//调用无参构造器
返回tmp构造函数。新实例((Object[])null);
} catch(InvocationTargetException e){
Unsafe.getUnsafe().抛出异常(e . gettargetexception());
//未达到
返回空
}
}复制代码
4. getConstructor0() 为获取匹配的构造方器;分三步:
1.先获取所有的构造函数,然后通过进行参数类型比较;
2.找到匹配后,通过反射工厂副本一份构造器返回;
3.否则抛出NoSuchMethodException
私有构造函数getconstructor 0(类?[]参数类型,
int which)抛出NoSuchMethodException
{
//获取所有构造器
constructor[]constructors=privateGetDeclaredConstructors((which==Member .PUBLIC));
for(构造函数构造函数:构造函数){
if(arrayContentsEq(参数类型、
构造函数。getparametertypes())){
返回getReflectionFactory().复制构造器(构造函数);
}
}
抛出新的nosuchmethodeexception(getName() .init argumentTypesToString(参数类型));
}复制代码
5. privateGetDeclaredConstructors(), 获取所有的构造器主要步骤;
1.先尝试从缓存中获取;
2.如果缓存没有,则从虚拟机(Java虚拟机的缩写)中重新获取,并存入缓存,缓存使用软引用进行保存,保证内存可用;
//获取当前类所有的构造方法,通过虚拟机(Java虚拟机的缩写)或者缓存
//返回"根"构造函数的数组。这些构造函数
//对象不能传播到外部世界,但必须
//而是通过反射工厂。复制构造函数复制。
私有构造函数[]privateGetDeclaredConstructors(仅布尔公共){
checkinited();
构造函数[]RES;
//调用reflectionData(),获取保存的信息,使用软引用保存,从而使内存不够可以回收
reflection datat rd=reflection data();
如果(rd!=null) {
res=publicOnly?研发。公共构造函数:rd。声明的构造函数;
//存在缓存,则直接返回
if (res!=空)返回表示留数
}
//没有可用的缓存值;从虚拟机请求值
if (isInterface()) {
@SuppressWarnings(未选中)
构造函数[]临时RES=(构造函数[])新构造函数?[0];
res=临时res
}否则{
//使用当地的方法从虚拟机(Java虚拟机的缩写)获取构造器
RES=getdeclaredconstructors 0(仅公共);
}
如果(rd!=null) {
//最后,将从虚拟机(Java虚拟机的缩写)中读取的内容,存入缓存
如果(仅公开){
rd.publicConstructors=res
}否则{
rd.declaredConstructors=res
}
}
返回表示留数
}
//延迟创建并缓存反射数据
反射数据处的私有反射数据(){
SoftReferenceReflectionDataT反射数据=this。反射数据;
int class redefinedcount=this。类redefinedcount
反射数据
如果(使用缓存
reflectionData!=空
(rd=reflectionData.get())!=空
研发。redefined count==classredefined count){
返回rd;
}
//否则没有软引用或清除的软引用或陈旧的反射数据
//-创建和替换新实例
返回newReflectionData(reflectionData,classRedefinedCount);
}
//新创建缓存,保存反射信息
私有反射datat newReflectionData(SoftReferenceReflectionDataT oldReflectionData,
int classRedefinedCount) {
如果(!使用缓存)返回空
//使用卡丝(人名)保证更新的线程安全性,所以反射是保证线程安全的
while (true) {
reflection datat rd=新的反射数据(classRedefinedCount);
//尝试对其进行国际体育仲裁法庭.
如果(原子。casreflectiondata(this,oldReflectionData,new SoftReference(rd))) {
返回rd;
}
//先使用国际体育仲裁法庭更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了
oldReflectionData=this。reflectiondata
class redefinedcount=this。类redefinedcount
if (oldReflectionData!=空
(rd=oldReflectionData.get())!=空
研发。redefined count==classredefined count){
返回rd;
}
}
}复制代码另外,使用relactionData()进行缓存保存;反射数据的数据结构如下!
//调用JVM TI重新定义类()时可能失效的反射数据
私有静态类ReflectionDataT {
可变字段[]声明了字段;
可变字段[]公共字段;
不稳定的方法[]声明了方法;
不稳定的方法[]公共方法;
易变结构声明了构造函数;
volatile constructor[]公共构造函数;
获取字段和getMethods的中间结果
可变字段[]声明了公共领域;
不稳定的方法[]声明了公共方法;
易变类?[]接口;
//创建此反射数据实例时classRedefinedCount的值
最终整数重定义计数
反射数据(int重新定义的计数){
这个。重新定义的计数=重新定义的计数;
}
}复制代码
6.通过上面,获取到 Constructor 了!接下来就只需调用其相应构造器的 newInstance(),即返回实例了!
//返回tmp构造函数。新实例((Object[])null);
//Java。郎。反思。构造器
@来电敏感
公共测试新实例(对象.initargs)
引发InstantiationException、IllegalAccessException、
IllegalArgumentException,InvocationTargetException
{
如果(!覆盖){
如果(!反思。快速检查成员访问(clazz,modifiers)) {
班级?呼叫者=反射。getcallerclass();
检查访问(调用者、clazz、null、修饰符);
}
}
if ((clazz.getModifiers()修饰符。枚举)!=0)
引发新的IllegalArgumentException("无法反射性地创建枚举对象");
ConstructorAccessor ca=构造函数访问器;//读取易失性
if (ca==null) {
ca=acquire constructor accessor();
}
@SuppressWarnings(未选中)
机构=(T)ca。新实例(initargs);
返回解语花
}
//孙。反思。delegatingconstructoraccessorimpl
公共对象newInstance(对象[]参数)
引发InstantiationException,
IllegalArgumentException,
InvocationTargetException
{
返回委派。新实例(参数);
}
//孙。反思。nativeconstructoraccessorimpl
公共对象newInstance(对象[]参数)
引发InstantiationException,
IllegalArgumentException,
InvocationTargetException
{
//我们不能膨胀属于伏特计匿名类的构造函数
//因为那种类不能被名字引用,所以不能
//从生成的字节码中找到。
if(numInvocations反射工厂。通货膨胀阈值()
!反映util。isfmannymousclass(c . getdeclaringclass()){
ConstructorAccessorImpl ACC=(ConstructorAccessorImpl)
新方法AccessorGenerator().
生成构造函数(c . getdeclaringclass(),
c.getParameterTypes(),
c.getExceptionTypes(),
c。get修饰符());
父母。设置代表(ACC);
}
//调用当地的方法,进行调用构造器
返回newInstance0(c,args);
}复制代码返回构造器的实例后,可以根据外部进行进行类型转换,从而使用接口或方法进行调用实例功能了。
以上就是超详细的虚拟机(Java虚拟机的缩写)反射原理技术点总结哦~的详细内容,更多请关注我们其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。