反射定义

1,JAVA反射机制是在运行状态中

对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性;

这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射提供的功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法

(如果属性是private,正常情况下是不允许外界操作属性值,这里可以用Field类的setAccessible(true)方法,暂时打开操作的权限)

反射的使用场景

  • Java编码时知道类和对象的具体信息,此时直接对类和对象进行操作即可,无需反射
  • 如果编码时不知道类或者对象的具体信息,此时应该使用反射来实现

反射源码解析

举例API :

Class.forName("com.my.reflectTest").newInstance()

1. 反射获取类实例 Class.forName("xxx");

  首先调用了 java.lang.Class 的静态方法,获取类信息!

注意:forName()反射获取类信息,并没有将实现留给了java,而是交给了jvm去加载!

主要是先获取 ClassLoader, 然后调用 native 方法,获取信息,加载类则是回调 入参ClassLoader 进类加载!

 @CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
// 先通过反射,获取调用进来的类信息,从而获取当前的 classLoader
Class<?> caller = Reflection.getCallerClass();
// 调用native方法进行获取class信息
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

2. java.lang.ClassLoader-----loadClass()

// java.lang.ClassLoader
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 先获取锁
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
// 如果已经加载了的话,就不用再加载了
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 双亲委托加载
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
} // 父类没有加载到时,再自己加载
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name); // this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
} protected Object getClassLoadingLock(String className) {
Object lock = this;
if (parallelLockMap != null) {
// 使用 ConcurrentHashMap来保存锁
Object newLock = new Object();
lock = parallelLockMap.putIfAbsent(className, newLock);
if (lock == null) {
lock = newLock;
}
}
return lock;
} protected final Class<?> findLoadedClass(String name) {
if (!checkName(name))
return null;
return findLoadedClass0(name);
}

3. newInstance()

newInstance() 其实相当于调用类的无参构造函数,主要做了三件事

  • 权限检测,如果不通过直接抛出异常;

  • 查找无参构造器,并将其缓存起来;

  • 调用具体方法的无参构造方法,生成实例并返回;

// 首先肯定是 Class.newInstance
@CallerSensitive
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
} // NOTE: the following code may not be strictly correct under
// the current Java memory model. // Constructor lookup
// newInstance() 其实相当于调用类的无参构造函数,所以,首先要找到其无参构造器
if (cachedConstructor == null) {
if (this == Class.class) {
// 不允许调用 Class 的 newInstance() 方法
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
// 获取无参构造器
Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw (InstantiationException)
new InstantiationException(getName()).initCause(e);
}
}
Constructor<T> tmpConstructor = cachedConstructor;
// Security check (same as in java.lang.reflect.Constructor)
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
// 调用无参构造器
return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}

4. getConstructor0() 为获取匹配的构造方器;分三步:

  1. 先获取所有的constructors, 然后通过进行参数类型比较;

  2. 找到匹配后,通过 ReflectionFactory copy一份constructor返回;

  3. 否则抛出 NoSuchMethodException;

private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
int which) throws NoSuchMethodException
{
// 获取所有构造器
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
for (Constructor<T> constructor : constructors) {
if (arrayContentsEq(parameterTypes,
constructor.getParameterTypes())) {
return getReflectionFactory().copyConstructor(constructor);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}

5. privateGetDeclaredConstructors(), 获取所有的构造器主要步骤;

  1. 先尝试从缓存中获取;

  2. 如果缓存没有,则从jvm中重新获取,并存入缓存,缓存使用软引用进行保存,保证内存可用;

// 获取当前类所有的构造方法,通过jvm或者缓存
// Returns an array of "root" constructors. These Constructor
// objects must NOT be propagated to the outside world, but must
// instead be copied via ReflectionFactory.copyConstructor.
private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) {
checkInitted();
Constructor<T>[] res;
// 调用 reflectionData(), 获取保存的信息,使用软引用保存,从而使内存不够可以回收
ReflectionData<T> rd = reflectionData();
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 {
// 使用native方法从jvm获取构造器
res = getDeclaredConstructors0(publicOnly);
}
if (rd != null) {
// 最后,将从jvm中读取的内容,存入缓存
if (publicOnly) {
rd.publicConstructors = res;
} else {
rd.declaredConstructors = res;
}
}
return res;
} // Lazily create and cache ReflectionData
private ReflectionData<T> reflectionData() {
SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
int classRedefinedCount = this.classRedefinedCount;
ReflectionData<T> rd;
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
return newReflectionData(reflectionData, classRedefinedCount);
} // 新创建缓存,保存反射信息
private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData,
int classRedefinedCount) {
if (!useCaches) return null; // 使用cas保证更新的线程安全性,所以反射是保证线程安全的
while (true) {
ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount);
// try to CAS it...
if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) {
return rd;
}
// 先使用CAS更新,如果更新成功,则立即返回,否则测查当前已被其他线程更新的情况,如果和自己想要更新的状态一致,则也算是成功了
oldReflectionData = this.reflectionData;
classRedefinedCount = this.classRedefinedCount;
if (oldReflectionData != null &&
(rd = oldReflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
return rd;
}
}
}

另外,使用 relactionData() 进行缓存保存;ReflectionData 的数据结构如下!

// reflection data that might get invalidated when JVM TI RedefineClasses() is called
private static class ReflectionData<T> {
volatile Field[] declaredFields;
volatile Field[] publicFields;
volatile Method[] declaredMethods;
volatile Method[] publicMethods;
volatile Constructor<T>[] declaredConstructors;
volatile Constructor<T>[] publicConstructors;
// Intermediate results for getFields and getMethods
volatile Field[] declaredPublicFields;
volatile Method[] declaredPublicMethods;
volatile Class<?>[] interfaces; // Value of classRedefinedCount when we created this ReflectionData instance
final int redefinedCount; ReflectionData(int redefinedCount) {
this.redefinedCount = redefinedCount;
}
}

6.通过上面,获取到 Constructor 了!接下来就只需调用其相应构造器的 newInstance(),即返回实例了!

// return tmpConstructor.newInstance((Object[])null);
// java.lang.reflect.Constructor
@CallerSensitive
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
// sun.reflect.DelegatingConstructorAccessorImpl
public Object newInstance(Object[] args)
throws InstantiationException,
IllegalArgumentException,
InvocationTargetException
{
return delegate.newInstance(args);
}
// sun.reflect.NativeConstructorAccessorImpl
public Object newInstance(Object[] args)
throws InstantiationException,
IllegalArgumentException,
InvocationTargetException
{
// We can't inflate a constructor belonging to a vm-anonymous class
// because that kind of class can't be referred to by name, hence can't
// be found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
new MethodAccessorGenerator().
generateConstructor(c.getDeclaringClass(),
c.getParameterTypes(),
c.getExceptionTypes(),
c.getModifiers());
parent.setDelegate(acc);
} // 调用native方法,进行调用 constructor
return newInstance0(c, args);
}

返回构造器的实例后,可以根据外部进行进行类型转换,从而使用接口或方法进行调用实例功能了。

总结

欢迎关注公众号:前程有光,领取一线大厂Java面试题总结+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结!

这些资料的内容都是面试时面试官必问的知识点,篇章包括了很多知识点,其中包括了有基础知识、Java集合、JVM、多线程并发、spring原理、微服务、Netty 与RPC 、Kafka、日记、设计模式、Java算法、数据库、Zookeeper、分布式缓存、数据结构等等。

建议收藏!超详细的JVM反射原理技术点总结的更多相关文章

  1. VMware 安装 Centos7 超详细过程

    https://www.runoob.com/w3cnote/vmware-install-centos7.html centos7安装参考文档 VMware 安装 Centos7 超详细过程 分类  ...

  2. 解密国内BAT等大厂前端技术体系-携程篇(长文建议收藏)

    1 引言 为了了解当前前端的发展趋势,让我们从国内各大互联网大厂开始,了解他们的最新动态和未来规划.这是解密大厂前端技术体系的第四篇,前三篇已经讲述了阿里.腾讯.百度在前端技术这几年的技术发展. 这一 ...

  3. 解密国内BAT等大厂前端技术体系-腾讯篇(长文建议收藏)

    1 引言 为了了解当前前端的发展趋势,让我们从国内各大互联网大厂开始,了解他们的最新动态和未来规划.这是解密大厂前端技术体系的第三篇,前两篇已经讲述了阿里和百度在前端技术这几年的技术发展.这一篇从腾讯 ...

  4. 解密国内BAT等大厂前端技术体系-美团点评之下篇(长文建议收藏)

    引言 在上篇中,我已经介绍了美团点评的业务情况.大前端的技术体系,其中大前端的技术全景图如下: 上篇重点介绍了工程化和代码质量的部分,工程化涵盖了客户端持续集成平台-MCI.全端监控平台-CAT.移动 ...

  5. 解密国内BAT等大厂前端技术体系-美团点评之上篇(长文建议收藏)

    引言 进入2019年,大前端技术生态似乎进入到了一个相对稳定的环境,React在2013年发布至今已经6年时间了,Vue 1.0在2015年发布,至今也有4年时间了. 整个业界在前端框架不断迭代中,也 ...

  6. [转帖]超详细的PostgreSQL体系结构总结,值得收藏

    超详细的PostgreSQL体系结构总结,值得收藏 https://www.toutiao.com/i6715390855772897800/ 原创 波波说运维 2019-07-26 00:03:00 ...

  7. Java多线程学习(吐血超详细总结)

    Java多线程学习(吐血超详细总结) 林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是java多线程的一个入门,其实 ...

  8. 超详细的Guava RateLimiter限流原理解析

    超详细的Guava RateLimiter限流原理解析  mp.weixin.qq.com 点击上方“方志朋”,选择“置顶或者星标” 你的关注意义重大! 限流是保护高并发系统的三把利器之一,另外两个是 ...

  9. 超详细的Java面试题总结(四 )之JavaWeb基础知识总结

    系列文章请查看: 超详细的Java面试题总结(一)之Java基础知识篇 超详细的Java面试题总结(二)之Java基础知识篇 超详细的Java面试题总结(三)之Java集合篇常见问题 超详细的Java ...

随机推荐

  1. CPU:Central Processing Unit

    CPU执行计算任务时都需要遵从一定的规范,程序在被执行前都需要先翻译为CPU可以理解的语言.这种规范或语言就是指令集(ISA,Instruction Set Architecture). CPU 架构 ...

  2. WebSocket的理解

    Websocket相对于无状态的HTTp协议,是在一次成功连接之后,在关闭请求之前,服务器和客户端能顺利进行信息传输.而不用像HTTP那样每一次都要告诉服务器这个请求者是谁(身份鉴别信息). 在HTT ...

  3. 如何将Nginx注册为系统服务,开机自启动。

    亲测有效! 一般程序员在实际工作中,除了敲代码,很少有机会实际接触操作其它东西,例如服务器环境搭建,项目部署等等,不是领导信任或项目组核心成员,应该是没有机会实际接触的,只能通过网上资料稍微了解一下. ...

  4. python基础二:循环

    python 中循环的方式有两种: 一,for 循环  单向循环 可以用来遍历字符串,列表,元组,字典等 for value in 被遍历对象: print(value) 遍历字典dict的时候稍有不 ...

  5. BP神经网络算法程序实现鸢尾花(iris)数据集分类

    作者有话说 最近学习了一下BP神经网络,写篇随笔记录一下得到的一些结果和代码,该随笔会比较简略,对一些简单的细节不加以说明. 目录 BP算法简要推导 应用实例 PYTHON代码 BP算法简要推导 该部 ...

  6. 同时使用mybatis和mybatis-plus时,pageHelper失效问题解决

    一.问题由来 最近刚拿到一个别人的项目,该项目中使用mybatis和mybatis-plus来操作数据库,我们需要在此基础上添加新功能. 做功能开发时一切都很顺利,我也很快完成了自己负责的模块,然后和 ...

  7. 已经编译安装的nginx/tenginx编译增加新模块

    只适用于自行编译安装的nginx配置 业务变更带来的Nginx增加模块需求 由于业务从php转为go开发,需要用到Http2的协议.这种协议在Nginx上需要http_v2_module这个模块的支持 ...

  8. 2018-12-7 CSAPP及C++

    今天虽然起床迟,但从结果上来看,学习效率还算不赖.从这几天的状况来看,为记录晚上上床后的学习内容,决定把在床上的学习内容算在后一天的学习中.那么从现在开始就可以协商英语的半个小时100个单词了. 英语 ...

  9. c语言博客作业——顺序结构,分支结构

    1.PTA截图 2.本章学习总结 2.1学习内容总结 数据的输入和输出:%d表示输入输出整数 %.lf表示输入浮点数 %.nf表示输出结果保留n位小数 if-else的分支结构可以有限个分类情况进行处 ...

  10. from `float` to `np.floating` is deprecated

    运行tensorflow测试程序时,出现:FutureWarning: Conversion of the second argument of issubdtype from `float` to ...