java反射与多线程_Java反射工作机制

前言

反射是Spring、mybatis等框架的基础,对于常写业务逻辑的同学应该算是最熟悉的陌生人,今天我们就聊聊Java的反射机制,把不熟悉变成熟悉。

结论在前:

1:Class对象包含类的所有信息,可以通过该对象获取到构造方法,成员变量,成员方法和接口等信息,这些信息在JVM中同样以类的形式存在

2:Class对象有三种获取方法,字面量XXX.class,Object.getClass(),Class.forName()

3:从Class对象中获取的Method、Field等类的组成元素的时候获取到的实际上是该Class对象内部的一个缓存中存储的Method、Field的拷贝。

4:调用Method的invoke方法底层借助了一个叫做MethodAccessor的工具,这个工具又两种形态,一种是native,一种是字节码生成加载后的Magic形态,前者初始化快执行慢,后者初始化慢执行快,JVM权衡之后决定前15次用前者,超过15次用后者(inflation机制)。

5:Class对象中的缓存创建使用了CAS+Volatile+死循环这种无锁形式

一、Class对象知多少

Class对象可以说是反射的源泉,但是Class对象存放在哪,什么时候存放,存放了哪些信息你真的了解吗?下面我们就来揭开Class对象的神秘面纱。

1、类生命周期知多少

这个比较简单,栈、堆、方法区、其他,栈存放引用,堆存放对象,方法区存放类信息和静态变量以及字面量,实际上Class对象就存放在方法区中。

1.1、类的生命周期

加载,连接(验证,准备,解析),初始化,使用,卸载;解析阶段与初始化阶段顺序不一定。

1.2、类的初始化时机

以下几种情况虚拟机必须对类进行初始化(加载,验证,准备自然必须在此之前)

首先:遇到new,getstatic,putstatic或invokestatic这4条字节码指令时,一般为实例化对象,读取或设置一个类的静态字段(final的除外),调用一个类的静态方法的时候

然后:使用java.lang.reflect包的方法对类进行反射调用的时候

再次:初始化一个类的时候首先初始化其父类

然后:虚拟机启动的时候首先会初始化主类(main方法的类)

最后:java.lang.invoke.MethodHandler实例最后的解析结果为Ref_getstatic,REF_putStatic,REF_invokeStatic的时候,这个方法对应的类需要触发初始化

从上面可以看出,当反射调用类的时候会触发类的加载。

1.3、类的加载过程

加载阶段需要完成的3件事情

首先:通过一个类的全限定名来获取定义此类的二进制字节流,实际上就是获取你已编译好的.class字节码文件

然后:将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

最后:在内存中生成一个代表这个类的java.lang.Class对象,作为方法区中这个类的各种数据的访问入口,这个对象存储在方法区中

重点就在这,Java的字节码Class信息会以Class对象的形式存放在方法区中!

二、类的结构信息知多少

让我们好好想想类有哪些信息组成,继承/实现的接口、全路径名、类名称、类访问限制、构造方法、成员变量、成员方法、静态变量等等。Class对象包含了所有获取这些信息的方法。这些信息中,反射最常用的是类的构造方法、成员变量、成员方法、成员方法参数这几个重要的属性,而且每个属性都有对应的类实现。

2.1、类信息的组成

516228c2acfd

类继承体系@2x.png

AnnotatedElement接口:该接口提供了获取注解信息的一些方法,即所有的参数、方法、成员变量、构造方法都能通过反射获取到注解的相关信息。

package类:对应Java包的一些信息

Parameter类:对应构造方法或者成员方法的参数信息,如参数访问限制,参数类型等等信息

AccessibleObject类:该类是成员变量、成员方法、构造方法们的父类,提供了一些public、private等修饰符的入口检查(是否可以访问、设置访问权限等)

GenericDeclaration类:提供泛型的一些信息

Field类:这个不用说了,对应成员变量

Executable类:顾名思义,可执行的,由两个子类,成员方法和构造方法,提供了两种方法公共的必要进行的一些操作,比如获取方法参数、获取方法名称、获取方法访问修饰符等等。

Method类:对应方法的类,提供了类的一些方法信息

Constructor类:对应构造方法的类,提供了构造方法的一些信息。

Class类:包含类的所有信息

其实使用反射关注最多的就是上面的Field、Method、Constructor三个类。

三、反射

解释了这么多类的信息,实际上都是为了反射做铺垫。那么究竟什么是反射呢?反射其实是在JVM运行的时候通过Class对象动态的获取类信息,这与我们平时编码有所差异的地方是反射不需要事先写好代码及用编译器编译,而是直接在JVM运行过程中拿到类的方法等信息直接执行。

3.1、如何获取Class对象

方法一:通过字面量直接获取,如XXX.class,值得注意的是这种字面量不会触发类的初始化,但此时方法区中肯定已经有了XXX类的Class对象,因此可以推断XXX类已经被加载到方法区,只是没有完成初始化,实际上初始化就是给类中定义的类变量和成员变量及静态代码块进行初始化赋值和执行操作,初始化完的类程序员才真正可以new出来。

方法二:通过Object类的getClass方法,如xxxObject.getClass(),这种方法会触发类的初始化哦

方法三:通过Class的静态方法forName(),这种方式也会触发类的初始化。

3.2、反射获取Field、Constructor、Method等

有了Class对象就可以为所欲为吗?抱歉,有Class对象真的可以为所欲为!

public class SingletonTest {

// 私有构造方法

private SingletonTest(){

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值