1 背景

前段时间组内针对“拷贝实例属性是应该用BeanUtils.copyProperties()还是MapStruct”这个问题进行了一次强烈的battle。反对MapStruct的同学给出了他厌弃BeanUtils的理由:因为用了反射,所以慢。这个理由一下子拉回了我边远的记忆,在我刚开始理解反射这个Java个性的时候,简直看到的每一篇文章都会有“Java反射不能频繁应用”、“反射影响性能”之类的话语,过后只是当一个论断记下了这些话,却没有深究过为什么,所以正好借此机会来探索一下Java反射的代码。

2 反射

包构造梳理反射相干的代码次要在jdk rt.jar下的java.lang.reflect包下,还有一些相干类在其余包门路下,这里先按下不表。依照继承和实现的关系先简略划分下java.lang.reflect包:① Constructor、Method、Field三个类型别离能够形容实例的构造方法、一般办法和字段。三种类型都间接或间接继承了AccessibleObject这个类型,此类型里次要定义两种办法,一种是通用的、对拜访权限进行解决的办法,第二种是可供继承重写的、与注解相干的办法。

② 只看选中的五种类型,咱们平时所用到的一般类型,譬如Integer、String,又或者是咱们自定义的类型,都能够用Class类型的实例来示意。Java引入泛型之后,在JDK1.5中裁减了其余四种类型,用于泛型的示意。别离是ParameterizedType(参数化类型)、WildcardType(通配符类型)、TypeVariable(类型变量)、GenericArrayType(泛型数组)。

③ 与②中形容的五种根本类型对应,下图这五个接口/类别离用来示意五种根本类型的注解相干数据。

④ 下图为实现动静代理的相干类与接口。java.lang.reflect.Proxy次要是利用反射的一些办法获取代理类的类对象,获取其构造方法,由此结构出一个实例。java.lang.reflect.InvocationHandler是代理类须要实现的接口,由代理类实现接口内的invoke办法,此办法会负责代理流程和被代理流程的执行程序组织。

3 指标

类实例的结构源码以String类的对象实例化为例,看一下反射是如何进行对象实例化的。Class<?> clz = Class.forName("java.lang.String");

String s =(String)clz.newInstance();
Class对象的结构由native办法实现,以java.lang.String类为例,先看看结构好的Class对象都有哪些属性:

能够看到目前只有name一个属性有值,其余属性临时都是null或者默认值的状态。下图是 clz.newInstance() 办法逻辑的流程图,接下来对其中次要的两个办法进行阐明:

从上图能够看出整个流程有两个外围局部。因为通常状况下,对象的结构都须要依附类里的构造方法来实现,所以第一局部就是拿到指标类对应的Constructor对象;第二局部就是利用Constructor对象,结构指标类的实例。3.1 获取Constructor对象首先上一张Constructor对象的属性图:

java.lang.Class#getConstructor0此办法中次要做的工作是首先拿到指标类的Constructor实例数组(次要由native办法实现),数组里每一个对象都代表了指标类的一个构造方法。而后对数组进行遍历,依据办法入参提供的parameterTypes,找到合乎的Constructor对象,而后从新发明一个Constructor对象,属性值与原Constructor统一(称为正本Constructor),并且正本Constructor的属性 root 指向源Constructor,相当于对源Constructor对象进行了一层封装。因为在getConstructor0()办法将返回值返回给调用方之后,调用方在后续的流程里进行了constructor.setAccesssible(true)的操作,这个办法的作用是敞开对constructor这个对象拜访时的Java语言拜访查看。语言拜访查看是个耗时的操作,所以正当猜想是为了进步反射性能敞开了这个查看,又出于平安思考,所以将最原始的对象进行了封装。

private Constructor<T> getConstructor0(Class<?>[] parameterTypes,                                    int which) throws NoSuchMethodException{//1、拿到Constructor实例数组并进行筛选    Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); //2、通过对入参的比拟筛选出符合条件的Constructor    for (Constructor<T> constructor : constructors) {        if (arrayContentsEq(parameterTypes,                            constructor.getParameterTypes())) {//3、创立正本Constructor            return getReflectionFactory().copyConstructor(constructor);        }    }    throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));}