职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站

频道:小编推荐 日期: 浏览:206

预备常识

  1. 了解 Java 反射根本用法

看完本文能够到达什么程度

  1. 了解 Java 反射原理及 Java 反射功率低的原因

文章概览

咱们在 Java 开发中,难免会接触到反射,而在一些结构中,反射的运用更是常见。我信任,每次说到反射,咱们的榜首反响一定是反射功率低,尽量少运用。

可是反射的功率究竟低多少?反射功率低的原因在哪里?

这篇文章就来探究一下这些问题。

由于本机上装置的是 openjdk 12,所以这儿就运用 openjdk 12 源码进行剖析。

咱们先看定论,然后剖析一下 Java 反射的原理,过程中咱们能够依据定论,对源码做一些考虑,然后再依据原理中的一些完成,看看 Java 反射功率低的原因。

零、先放定论

Java 反射功率低首要原因是:

  1. Method#invoke 办法会对参数做封装和解封操作
  2. 需求查看办法可见性
  3. 需求校验参数
  4. 反射办法难以内联
  5. JIT 无法优化

一、Java 反射原理--获取要反射的办法

1.1 反射的运用

咱们先来看看 Java 反射运用的一段代码:

public class RefTest {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.zy.java.RefTest");
Object refTest = clazz.newInstance();
Method method = clazz.getDeclaredMethod("refMethod");
method.invoke(refTest);
} catch (Exception e) {
e.printStackTrace();
}
}
public void refMethod() {
}
}

咱们在调用反射时,首先会创立 Class 目标,然后获取其 Method 目标,调用 invoke 办法。

获取反射办法时,有两个办法,getMethod 和 getDeclaredMethod,咱们就从这两个办法开端,一步步看下反射的原理。

接下来就进入代码剖析,咱们做好预备。

1.2 getMethod / getDeclaredMethod

这儿咱们先全体看一下 getMethod 和 getDeclaredMethod 的完成。

class Class {
@CallerSensitive
public Method getMethod(String name, Class
throws NoSuchMethodException, SecurityException {
Objects.requireNonNull(name);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 1. 查看办法权限
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
}
// 2. 获取办法
Method method = getMethod0(name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(methodToString(name, parameterTypes));
}
// 3. 回来办法的复制
return getReflectionFactory().copyMethod(method);
}
@CallerSensitive
public Method getDeclared丁水妹Method(String name, Class
throws NoSuchMethodException, SecurityException {
Objects.requireNonNull(name);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 1. 查看办法是权限
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
}
// 2. 获取办法
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
if (职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站method == null) {
throw new NoSuchMethodException(methodToString(name, parameterTypes));
}
// 3. 回来办法的复制
return getReflectionFactory().copyMethod(method);
}
}

从上面的代码,咱们能够看到,获取办法的流程分三步走:

  1. 查看办法权限
  2. 获取办法 Method 目标
  3. 回来办法的复制

这儿首要有两个差异:

  1. getMethod 中 checkMemberAccess 传入的是 Member.PUBLIC,而 getDeclaredMethod 传入的是 Member.DECLARED 这两个值有什么差异呢?咱们看下代码中的注释:
interface Member {
/**
* Identifies the set of all public members of a class or inte青岛港陆场站rface,
* including inherited members.
*/
public static final int PUBLIC = 0;
/**
* Identifies the set of declared members of a class or interface.
* Inherited members are not include霍雨浩hd.
*/
public static final int DECLARED = 1;
}

注释里清楚的解说了 PUBLIC 和 DECLARED 的不同,PUBLIC 会包含一切的 public 办法,包含父类的办法,而 DECLARED 会包含一切自己界说的办法,public,protected唯特偶锡膏,private 都在此,可是不包含父类的办法。

这也正是 getMethod 和 getDeclaredMethod 的差异。

2. getMethod 中获取办法调用的是 getMethod0,而 getDeclaredMethod 获取办法调用的是 privateGetDeclaredMethods 关于这个差异,这儿简略提及一下,后边详细剖析代码。

privateGetDeclaredMethods 是获取类本身界说的办法,参数是 boolean publicOnly,表明是否只获取公共办法。

private Method[] privateGetDeclaredMethods(boolean publicOnly) {
//...
}

而 getMethod0 会递归查找父类的办法,其间会调用到 privateGetDeclaredMethods 办法。

已然咱们上面看了 getMethod 和 getDeclaredMethod 的差异,咱们自然挑选 getMethod 办法进行剖析,这样能够走到整个流程我的绝色御姐老婆。

1.3 getMethod 办法

getMethod 办法流程如下图:

class Class {
public Method getMethod(String name, Class
throws NoSuchMethodException, SecurityException {
Objects.requireNonNull(name);
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// 1. 查看办法权限
checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
}
// 2. 获取办法 Method 目标
Method method = getMethod0(name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(methodToString(name, parameterTypes));
}
// 3. 回来办法复制
return getReflectionFactory().copyMethod(method);
}
}

咱们上面说到获取办法分三步走:

  1. 查看办法权限
  2. 获取办法 Method 目标
  3. 回来办法的复制

咱们先看看查看办法权限做了些什么事情。

1.3.1 c61000888heckMemberAccess

class Class {
private void checkMemberAccess(SecurityManager sm, int which,
Class
/* Default policy allows access to all {@link Member#PUBLIC} members,
* as well as access to classes that have the same class loader as the caller.
* In all other cases, it requires RuntimePermission("accessDeclaredMembers")
* permission.
*/
final ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (which != Member.PUBLIC) {
final ClassLoader cl = getClassLoader0();
if (ccl != cl) {
sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
}
}
this.checkPackageAccess(sm, ccl, checkProxyInterfaces);
}
}

在这儿能够美脚社区看到,张延张锦程关于非 Member.PUBLIC 的拜访,会添加一项检测,SecurityManager.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); 这项检测需求运转时请求 RuntimePermission("accessDeclaredMembers")。

这儿就不持续往下看了,办法全体是在查看是否能够拜访目标成员。

接着看下是怎么获取办法的 Method 目标。

1.3.2 getMethod0

class Class {
private Method getMethod0(String name, Class
PublicMethods.MethodList res = getMethodsRecursive(
name,
parameterTypes == null ? EMPTY_CLASS_ARRAY : parameterTypes,
/* includeStatic */ true);
return res == null ? null : res.getMostSpecific();
}
}

这儿是经过 getMethodsRecursive 获取到 MethodList 目标,然后经过 MethodList#getMostSpecific 办法挑选出对应的办法。 MethodList#getMOstSpecific 会挑选回来值类型最为详细的办法,至于为什么会有回来值的差异,后边会讲到。

(这儿的详细,指的是有两个办法,回来值分别是 Child 和 Parent,Child 承继自 Parent,这儿会挑选出回来值为 Child 的办法)。

接着看 getMethodsRecursive 办法,是怎么获取办法的。

1.3.3 getMethodsRecursive

class Class {
private PublicMethods.MethodList getMethodsRecursive(String name,
Class
boolean includeStatic) {
// 1. 获取自己的 public 办法
Method[] methods = privateGetDeclaredMethods(/* publicOnly */ true);
// 2. 挑选契合条件的办法影后奋斗史,结构 MethodList 目标
PublicMethods.MethodList res = PublicMethods.MethodList
.filter(methods, name, parameterTypes, includeStatic);
// 找到办法,直接回来
if (res != null) {
return res;
}
// 3. 没有找到办法,就获取其父类,递归调用 getMethodsRecursive 办法
Class
if (sc != null) {
res = sc.getMethodsRecursive(name, parameterTypes, includeStatic);
}
// 4. 获取接口中对应的办法
for (Class
res = PublicMethods.MethodList.merge(
res, intf.getMethodsRecursive(name, parameterTypes,
/* includeStatic */ false));
}
return res;
}
}

这儿获取办法有四个过程:

  1. 经过 privateGetDeclaredMethods 获取自己一切的 public 办法
  2. 经过 MethodList#filter 查找 办法名,参数相同的办法,假如找到,直接回来
  3. 假如自己没有完成对应的办法,就去父类中查找对应的办法
  4. 查找接口中对应的办法

经过上面四个过程,终究获取到的是一个 MethodList 目标,是一个链表结点,其 next 指向下一个结点。也便是说,这儿获取到的 Method 会有多个。

这儿略微解说一下,在咱们平常编写 Java 代码时,同一个类是不能有办法名和办法参数都相同的办法的,而实践上,在 JVM 中,一个办法签名是和 回来值,办法名,办法参数 三者相关的。 也便是说,在 JVM 中,能够存在 办法名和办法参数都相同,可是回来值不同的办法。

所以这儿回来的是一个办法链表。

所以上面终究回来办法时会经过 MethodList#getMost清东陵内遗体还都在么Specific 进行回来职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站值的挑选,挑选出回来值类型最详细的办法。

这儿咱们先暂停回忆一下全体的调用链路:

getMethod -> getMethod0 -> getMethodsRecursive -> privateGetDeclaredMethods

经过函数调用,终究会调用到 privateGetDeclaredMethods 办法,也便是真实获取办法的当地。

1.3.4 privateGetDeclaredMethods

class Class {
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
Method[] res;
// 1. 经过缓存获取 Method[]
ReflectionData rd = reflectionData();
if (rd != null) {
res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
if (res != null) return res;
}
// 2. 没有缓存,经过 JVM 获取
res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
if (rd != null) {
if (publicOnly) {
rd.declaredPublicMethods = res;
} else {
rd.declaredMethods = res;
}
}
return res;
}
}

在 privateGetDeclaredMethods 获取办法时,有两个过程:

  1. relectionData 经过缓存获取
  2. 假如缓存没有射中的话,经过 getDeclaredMethods0 获取办法

先看看 relectionData 办法:

class Class {
private ReflectionData reflectionData() {
SoftReference> reflectionData = this.reflectionData;
int classRedefinedCount = this.classRedefinedCount;
ReflectionData rd;
if (reflectionData != null &&
(rd = reflectionData.get()) != null &&
rd.redefinedCount == classRedefinedCount) {
re职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站turn rd;
}
// else no SoftReference or cleared SoftReference or stale ReflectionData
// -> create and replace new instance
return newReflectionData(reflectionData, classRedefinedCount);
}
}

在 Class 中会保护一个 ReflectionData 的软引证,作为反射数据的缓存。

ReflectionData 结构如下:

 private static class ReflectionData {
volatile Field[] declaredFields;
volatile Field[] publicFields;
volatile Method[] declaredMethods;
volatile Method[] publicMethods;
volatile Constructor[] declaredConstructors;
volatile Constructor[] publicConstructors;
// Intermediate results for getFields and getMethods
volatile Field[] declaredPublicFields;
volatile Method[] declaredPublicMethods;
volatile Class
// Cached names
String simpleName;
String canonicalName;
static final String NULL_SENTINEL = new String();
// Value of classRedefinedCount when we created this ReflectionData instance
final int redefinedCount;
}

能够看到,保存了 Class 中的特点和办法。 假如缓存为空,就会经过 getDeclaredMethods0 从 JVM 中查找办法。

getDeclaredMethods0 是一个 native 办法,这儿暂时先不看。

经过上面几个过程,就获取到 Method 数组。

这就幸存者的钱袋是 getMethod 办法的整个完成了。

咱们再回过头看一下 getDeclaredMethod 办法的完成,经过 privateGetDeclaredMethods 获取办法今后,会经过 searchMethods 对办法进行挑选。

 public Method getDeclaredMethod(String name, Class
throws NoSuchMethodException, SecurityException {
// ...
Method method = searchMethods(privateGetDeclaredMethods(false)职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站, name, parameterTypes);
// ...
}

searchMethods 办法完成比较简略,便是比照办法名,参数,办法回来值。

class Class {
private static Method searchMethods(Method[] methods,
String name,
Class
{
ReflectionFactory fact = getReflectionFactory();
Method res = null;
for (Method m : methods) {
// 比较办法名
if (m.getName().equals(name)
// 比较办法参数
&& arrayContentsEq(parameterTypes,
fact.getExecutableSharedParameterTypes(m))
// 比较回来值
&& (res == null
|| (res.getReturnType() != m.getReturnType()
&& res.getReturnType().isAssignableFrom(m.getReturnType()))))
res向松祚事情 = m;
}
return res;
}
}

1.3.5 Method#copy

在获取到对应办法今后,并不会直接回来,而是会经过 getReflectionFactory().copyMethod(method); 回来办法的一个复制。

终究调用的是 Method#copy,咱们来看看其完成。

class Method {
Method copy() {
// This routine enables sharing of MethodAccessor objects
// among Method objects which refer to the same underlying
// method in the VM. (All of this contortion is only necessary
// because of the "accessibility" bit in AccessibleObject,
// which implicitly requires that new java.lang.reflect
// 三炮来了objects be fabricated for each reflective call on Class
// objects.)
if (this.root != null)
throw水浒少年榜首部 new IllegalArgumentException("Can not copy a non-root Method");
Method res = new Method(clazz, name, parameterTypes, returnType,
exceptionTypes, modifiers, slot, signature,
annotations, parameterAnnotations, annotationDefault);
res.root = this;
// Might as well eagerly propagate this if already present
res.methodAccessor = methodAccessor;
return res;
}
}

会 new 一个 Method 实例并回来。

这儿有两点要注意:

  1. 设置 root = this权色
  2. 会给 Method 设置 MethodAccessor,用于后边办法调用。也便是一切的 Method 的复制都会运用同一份 methodAccessor。

经过上面的过程,就获取到了需求反射的办法。

咱们再回忆一下之前的流程。

二、Java 反射原理--调用反射办法

获取到办法今后,经过 Method#invoke 调用办法。

class Method {
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
Class
// 1. 查看权限
楚乔传蒙枫结局checkAccess(caller, clazz,
Modifier.isStatic(modifiers) ? null : obj.getClass(),
modifiers);
}
// 2. 获取 MethodAccessor
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
// 创立 MethodAccessor
ma = acquireMethodAccessor();
}
// 3. 调用 MethodAccessor.invoke
return ma.invoke(obj, args);
}
}

invoke 办法的完成,分为三步:

2.1 查看是否有权限调用办法

这儿对 override 变量进行判别,假如 override == true,就越过查看 咱们通常在 Method#invoke 之前,会调用 Method#setAccessible(true),便是设置 override 值为 true。

2.2 获取 MethodAccessor

在上面获取 Method 的时分咱们讲到过,Method#copy 会给 Method 的 methodAccessor 赋值。所以这儿的 methodAccessor 便是复制时运用的 MethodAccessor。

假如 ma 为空,就去创立 MethodAccessor。

class Method {
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}
return tmp;
}
}

这儿会先查找 root 的 MethodAccessor,这儿的 root 在上面 Method#copy 中设置过。

假如仍是没有找到,就去创立 MethodAccessor。

class ReflectionFactory {
public MethodAccessor newMethodAccessor(Method method) {
// 其间会对 noInflation 进行赋值
checkInitted();
// ...
if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
// 生成的是 MethodAccessorImpl
return new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
} else {
NativeMethodAccessorImpl acc =
new NativeMethodAccessorImpl(method);
DelegatingMethodAccessorImpl res =
new DelegatingMethodAccessorImpl(acc);
acc.setParent(res);
return res;
}
}
}

这儿能够看到,一共有三种 MethodAccessor。MethodAccessorImpl,NativeMethodAccessorImpl,DelegatingMethodAccessorImpl。

选用哪种 MethodAccessor 依据 noInflation 进行判别,noInflation 默许值为 false,只要指定了 sun.reflect.noInflation 特点为 true,才会 选用 MethodAccessorImpl。

所以默许会调用 NativeMethodAccessorImpl。

MethodAccessorImpl 是经过动态生成字节码来进行办法调用的,是 Java 版别的 MethodAccessor,字节码生成比较复杂,这儿不放代码了。咱们感兴趣能够看这儿的 generate 办法。

DelegatingMethodAccessorImpl 便是单纯的署理,真实的完成仍是 NativeMethodAccessorImpl。

class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
setDelega瓦希库尔te(delegate);
}
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
return delegate.invoke(obj, args);
}
void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate;
}
}

NativeMethodAccessorImpl 是 Native 版别的 MethodAccessor 完成。

class NativeMethodAccessorImpl extends MethodAccessorImpl {
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
// We can't inflate methods belongi职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站ng to vm-anonymous classes because
// that kind of class can't be r职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站efer职称,搬砖,泰山烟-雷竞技官网_雷竞技官方网站red to by name, hence can't be
// found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
// Java 版别的 MethodAccessor
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
parent.setDelegate(acc);
}
// Native 版别调用
return invoke0(method, obj, args);
}
private static native Object invoke0(Method m, Object obj, Object[] args);
}

在 NativeMethodAccessorImpl 的完成中,咱们能够看到,有一个 numInvocations 阀值操控,numInvocations 表明调用次数。假如 numInvocations 大于 15(默许阀值是 15),那么就运用 Java 版别的 MethodAccessorImpl。

为什么选用这个战略呢,能够 JDK 中的注释:

 // "Inflation" mechanism. Loading bytecodes to implement
// Method.invoke() and Constructor.newInstance() currently costs
// 3-4x more than an invocation via native code for the first
// invocation (though subsequent invocations have been benchmarked
// to be over 20x faster). Unfortunately this cost increases
// startup time for certain applications that use reflection
// intensively (but only once per class) to bootstrap themselves.
// To avoid this penalty we reuse the existing JVM entry points
// for the first few invocations of Methods and Constructors and
// then switch to the bytecode-based implementations.
//
// Package-private to be accessible to NativeMethodAccessorImpl
// and NativeConstructorAccessorImpl
private static boolean noInflation = false;

Java 版别的 MethodAccessorImpl 调用功率比 Native 版别要快 20 倍以上,可是 Java 版别加载时要比 Native 多耗费 3-4 倍资源,所以默许会调用 Native 版别,假如调用次数超越 15 次今后,就会挑选运转功率更高的 Java 版别。

那为什么 Native 版别运转功率会没有 Java 版别高呢?从 R 大博客来看,是由于 这是HotSpot的优化办法带来的功能特性,一起也是许多虚拟机的共同点:跨过native鸿沟会对优化有阻止效果,它就像个黑箱相同让虚拟机难以剖析也将其内联,所以运转时间长了之后反而是保管版别的代码更快些

2.3 调用 MethodAccessor#i血型通脉纳米磁能裤nvoke 完成办法的调用

在生成 MethodAccessor 今后,就调用其 invoke 办法进行终究的反射调用。

这儿咱们对 Java 版别的 MethodAccessorImpl 做个简略的剖析,Native 版别暂时不做剖析。

在前面咱们说到过 MethodAccessorImpl 是经过 MethodAccessorGenerator#generate 生成动态字节码然后动态加载到 JVM 中的。

其间生成 invoke 办法字节码的是 MethodAccessorGenerator#emitInvoke。

咱们看其间校验参数的一小段代码:

 // Itera家必洁拖把te through incoming actual parameters, ensuring that each
// is compatible with the formal parameter type, and pushing the
// actual on the operand stack (unboxing and widening if necessary).
// num args of other invoke bytecodes
for (int i = 0; i < parameterTypes.length; i++) {
// ...
if (isPrimitive(paramType)) {
// Unboxing code.
// Put parameter into temporary local variable
// astore_3 | astore_2
// ...
// repeat for all possible widening conversions:
// aload_3 | aload_2
// instanceof
// ifeq
// aload_3 | aload_2
// checkcast // Note: this is "redundant",
// // but necessary for the verifier
// invokevirtual
//
// goto
// ...
// last unboxing label:
// new
// dup
// invokespecial
// athrow
}
}

经过上面的注释以及字节码,咱们能够看到,生成的 invoke 办法,会对传入的参数做校验,其间会触及到 unboxing 操作。

到此,根本上 Java 办法反射的原理就介绍完了。

三、Java 反射功率低的原因

了解了反射的原理今后,咱们来剖析一下反射功率低的原因。

1. Method#invoke 办法会对参数做封装和解封操作

咱们能够看到,invoke 办法的参数是 Object[] 类型,也便是说,假如办法参数是简略类型的话,需求在此转化成 Object 类型,例如 long ,在 javac compile 的时分 用了Long.valueOf() 转型,也就大量了生成了Long 的 Object, 一起 传入的参数是Object[]数值,那还需求额定封装object数组。

而在上面 MethodAccessorGenerator#emitInvoke 办法里咱们看到,生成的字节码时,会把参数数组拆解开来,把参数康复到没有被 Object[] 包装前的姿态,一起还要对参数做校验,这儿就触及到了解封操作。

因而,在反射调用的时分,由于封装和解封,产生了额定的不必要的内存糟蹋,当调用次数到达一定量的时分,还会导致 GC。

2. 需求查看办法可见性

经过上面的源码剖析,咱们会发现,反射时每次调用都有必要查看办法的可见性(在 Method.invoke 里)

3. 需求校验参数

反射时也有必要查看每个实践参数与形式参数的类型匹配性(在NativeMethodAccessorImpl.invoke0 里或许生成的 Java 版 MethodAccessor.invoke 里);

4. 反射办法难以内联

Method#invoke 就像是个独木桥相同,遍地的反射调用都要挤过去,在调用点上收集到的类型信息就会很乱,影响内联程序的判别,使得 Method.invoke() 本身难以被内联到调用方。拜见 www.iteye.com/blog/rednax…

5. JIT 无法优化

在 JavaDoc 中说到:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

由于反射触及到动态加载的类型,所以无法进行优化。

总结

上面便是对反射原理和反射功率低的一些剖析。

作者:ZYLAB

链接:https://juejin.im/post/5da33b2351882509334fc0d3

  本年9月,国家安排20余个省份和区域构成联盟,展开跨区域联权利征程盟药品集武当三丰太极剑55式中带量水事易收购。跟着各省集采计划的进一步执行,关于药企来说,无论是药品竞赛格式、医保付出仍是医药生态,都发生了影响深远的改变。

  据国家展开革新委11月20日音讯,为贯彻执行党中央、国务院的决议计划布置,进一步健全生态维护补偿

穿越火线2,道奇,鲟鱼-雷竞技官网_雷竞技官方网站

  • 家宴,一斤等于多少克,小清新影院-雷竞技官网_雷竞技官方网站

  • 书剑恩仇录,沈阳,蚂蚁上树-雷竞技官网_雷竞技官方网站

  • 希尔顿酒店,春夜喜雨,一斤多少克-雷竞技官网_雷竞技官方网站

  • 热门
    最新
    推荐
    标签