JVM原理解读——反射

JVM原理解读——反射


以一个简单的例子开始:

public class User {

    private Integer age;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
User user = new User();
        Class<?> kClass = Class.forName("com.company.User");
        Method method = kClass.getMethod("setAge", Integer.class);
        for (int i=0;i<15;i++){
            method.invoke(user,i);
        }

1、Class.forName——获取类

@CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
      	//获取调用者,是个native方法
        Class<?> caller = Reflection.getCallerClass();
      	//使用调用者的类加载器寻找目标类,也是native方法
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

2、getMethod——获取目标方法

@CallerSensitive
    public Method getMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
      	//跟SystemSecurity有关,一般都是空,跳过
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
      	//获取类的所有方法
        Method method = getMethod0(name, parameterTypes, true);
        if (method == null) {
            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
        }
        return method;
    }

获取类的所有方法调用getMethod0

private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
    MethodArray interfaceCandidates = new MethodArray(2);
    Method res =  privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates);
    if (res != null)
        return res;

    // Not found on class or superclass directly
    interfaceCandidates.removeLessSpecifics();
    return interfaceCandidates.getFirst(); // may be null
}
private Method privateGetMethodRecursive(String name,
        Class<?>[] parameterTypes,
        boolean includeStaticMethods,
        MethodArray allInterfaceCandidates) {
    Method res
    //获取类的类的所有公有方法
    if ((res = searchMethods(privateGetDeclaredMethods(true),
                             name,
                             parameterTypes)) != null) {
        if (includeStaticMethods || !Modifier.isStatic(res.getModifiers()))
            return res;
    }
    //找父类
    if (!isInterface()) {
        Class<? super T> c = getSuperclass();
        if (c != null) {
            if ((res = c.getMethod0(name, parameterTypes, true)) != null) {
                return res;
            }
        }
    }
    //找接口
    Class<?>[] interfaces = getInterfaces();
    for (Class<?> c : interfaces)
        if ((res = c.getMethod0(name, parameterTypes, false)) != null)
            allInterfaceCandidates.add(res);
    // Not found
    return null;
}

获取类的所有方法调用privateGetDeclaredMethods

private Method[] privateGetDeclaredMethods(boolean publicOnly) {
    checkInitted();
    Method[] res;
    ReflectionData<T> rd = reflectionData();
    if (rd != null) {
        res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
        if (res != null) return res;
    }
    //getDeclaredMethods0才是真正获取类的所有方法,之前的不过都是嵌套加细节处理
  	//然后通过反射过滤获取匹配的方法,
  	//这里我们就获取到了setAge方法
    res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
    if (rd != null) {
        if (publicOnly) {
            rd.declaredPublicMethods = res;
        } else {
            rd.declaredMethods = res;
        }
    }
    return res;
}

3、invoke——执行方法

@CallerSensitive
    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        //初始化MethodAccessor
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        //通过MethodAccessor执行invoke
        return ma.invoke(obj, args);
    }

初始化的是DelegatingMethodAccessorImpl,调用它的invoke方法

public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        return this.delegate.invoke(var1, var2);
    }

是NativeMethodAccessorImpl中invoke方法的封装,这样的实现也叫本地实现

//该方法通过本地实现的次数,当达到阈值,会将实现转化为动态字节码实现
private int numInvocations;
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
  			//inflationThreshold获取反射调用的域值,默认为15,可以通过-Dsun.reflect.inflationThreshold=调整
  			//当反射调用次数确实很频繁,可以通过-Dsun.reflect.noInflation=true从第一次调用就直接使用字节码实现
  			//从语义上看匿名类是无法通过字节码实现的
        if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
          	//升成该方法的字节码
            MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
          	//将本地实现替换为字节码实现
            this.parent.setDelegate(var3);
        }
				//执行方法调用
  			//本地实现是调用native方法
  			//字节码实现是解析内存中对应方法的字节码
        return invoke0(this.method, var1, var2);
    }

生成对应方法的字节码调用generateMethod,是generate方法的封装

public MethodAccessor generateMethod(Class<?> var1, String var2, Class<?>[] var3, Class<?> var4, Class<?>[] var5, int var6) {
    return (MethodAccessor)this.generate(var1, var2, var3, var4, var5, var6, false, false, (Class)null);
}
private MagicAccessorImpl generate(final Class<?> var1, String var2, Class<?>[] var3, Class<?> var4, Class<?>[] var5, int var6, boolean var7, boolean var8, Class<?> var9) {
  			//asm是java的字节码技术,底层是使用ByteVector将字节码放在内存中
        ByteVector var10 = ByteVectorFactory.create();
        this.asm = new ClassFileAssembler(var10);
        this.declaringClass = var1;
        this.parameterTypes = var3;
        this.returnType = var4;
        this.modifiers = var6;
        this.isConstructor = var7;
        this.forSerialization = var8;
  			//都是进行字节码操作,挑一个简单的看
        this.asm.emitMagicAndVersion();
  			//以下省略...
    }

调用emitMagicAndVersion往ByteVector里写字节码

public void emitMagicAndVersion() {
  			//-889275714换算成16进制就是cafebabe,是java文件的标识
        this.emitInt(-889275714);
  			//asm生成的字节码好像把版本固定到1.5了
        this.emitShort((short)0);
        this.emitShort((short)49);
    }

4、方法内联的失效

​ JVM记录每个反射调用方法的类型是有限的,靠后调用的方法会导致JVM优化方法内联失败,增加栈帧出入的消耗。可以通过-XX:TypeProfileWidth=调整,默认值是2。我并没有找到profile相关的源码,如果有读者接触过希望可以互相分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wheat_Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值