HotSpot 反射

news/2024/5/19 6:03:36 标签: hotspot, 反射, invoke

Java是一门静态语言,但是Java的反射赋予了Java动态的能力。Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。反射功能可以让我们在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

一.Class

在HotSpot内部通过Klass模型来表示Java类的方法字段访问权限父类子类等信息。这为Java的反射提供了HotSpot内部表征信息,通过将Kclass对称到语言Java语言层面的Class类,我们就获得了反射能力。通过Object的getClass()方法,这种能力被每个类拥有。

java/lang/Object.java

public class Object {
	@HotSpotIntrinsicCandidate
    public final native Class<?> getClass();
}

jdk/src/java.base/share/native/libjava/Object.c

NIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env, jobject this)
{
    if (this == NULL) {
        JNU_ThrowNullPointerException(env, NULL);
        return 0;
    } else {
        return (*env)->GetObjectClass(env, this);
    }
}

hotspot/src/share/vm/prims/jni.cpp

JNI_ENTRY(jclass, jni_GetObjectClass(JNIEnv *env, jobject obj))
  JNIWrapper("GetObjectClass");

  HOTSPOT_JNI_GETOBJECTCLASS_ENTRY(env, obj);

  Klass* k = JNIHandles::resolve_non_null(obj)->klass();
  jclass ret =
    (jclass) JNIHandles::make_local(env, k->java_mirror());

  HOTSPOT_JNI_GETOBJECTCLASS_RETURN(ret);
  return ret;
JNI_END

此外通过Class.forName方法也可以返回运行时类,通过forName0和调用类的类加载器加载运行时类型信息

java/lang/Class.java

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
     @CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }
}

从当前线程的栈帧中找到正在执行的Java方法,由此方法来确定调用类

jdk/src/java.base/share/native/libjava/Reflection.c

JNIEXPORT jclass JNICALL
Java_jdk_internal_reflect_Reflection_getCallerClass__(JNIEnv *env, jclass unused)
{
    return JVM_GetCallerClass(env, JVM_CALLER_DEPTH);
}

在Class类中提供了查询运行时类信息的方法,包括查询运行时类的字段,方法,注解,接口,构造函数,泛型信息,父类,访问权限等。这些信息赋予了上层框架搭建更多的灵活性。诸如实现注解处理器,动态代理,IOC,动态加载等特性。

二.reflect

java/lang/reflect在这里插入图片描述
在Java平台框架层的reflect包下提供了一组运行时类反射操作类,通过进一步抽象运行时的类型信息,提取出诸如字段,方法,构造函数,数组,类型参数,类型,泛型,注解,访问修饰符等Java语言要素,并使用Java类来表示这些信息,为上层应用提供强大的反射能力。

jdk/internal/reflect
在这里插入图片描述
internal.reflect包赋予反射更强的能力,使得访问类的常量池信息,方法字段的字节码编辑等。通过InvocationHandler,Proxy,ProxyGenerator和jdk.internal.reflect包为上层应用提供动态生成类的代理能力。

invoke_78">三.invoke

在这里插入图片描述
对于反射在refect包下的类方法特性已经够用了,那么在invoke包下的反射特新则更进一步。refect包的动态是作用在虚拟机内部的,而invoke的动态能力则在字节码上,更加灵活,更像是在Java语法规则内手写字节码:自己创建方法签名(MethodType),自己决定调用方式(invokestatic/invokespecial/invokevirtual),自己注意访问控制(public/package/protected/private),最后还要自己决定类型隐式转换。invoke包配合reflect包为其他动态语言运行于虚拟机上提供了可能,如Scale,JPython,Kotlin等。

四.总结

  1. Reflection中的java.lang.reflect.Method对象远比MethodHandle机制信息含量多,换句话说,Reflection是重量级,而MethodHandle是轻量级
  2. Relection和MethodHandle机制都是在模拟方法调用,但Reflection是在模拟Java代码层次的方法调用,而MethodHandle是在模拟字节码层次的方法调用。在MethodHandles.lookup中的3个方法-findStaitc、findVirtual、findSpecial正是为了对应于invokestatic、invokevirtual和invokespecial这几条字节码指令的执行权限校验行为,而这些底层细节在使用Reflection API时是不需要关心的
  3. 由于MethodHandle是对字节码的方法指令调用的模拟,所以理论上虚拟机做了各种优化
  4. Reflection API的设计目标是只为Java语言服务的,而MethodHandle则设计成可服务于所有Java虚拟机之上的语言,其中也包括Java

http://www.niftyadmin.cn/n/1315372.html

相关文章

EventBus使用详解(一)——初步使用EventBus(http://blog.csdn.net/harvic880925/article/details/40660137)...

一、概述 EventBus是一款针对Android优化的发布/订阅事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment&#xff0c;Activity&#xff0c;Service&#xff0c;线程之间传递消息.优点是开销小&#xff0c;代码更优雅。以及将发送者和接收者解耦。1、下载EventBus的类…

HotSpot Net

HotSpot对上层Java网络的支持主要通过Socket来支持。通过套接在TCP/IP传输控制协议层和HTTP/FTP/SMTP应用层之间搭建桥梁。传输控制层用操作系统层面实现。上层协议借助Socket进一步实现&#xff0c;Java平台已为我们实现了方便的应用层协议。如需自行实现自定义协议&#xff0…

怎样实现ZBrush中的智能对称

ZBrush软件智能化和人性化的工作流程让用户在创作中提高工作效率&#xff0c;体验创作乐趣&#xff0c;说起智能化不得不提的就是ZBrush给我们提供的智能对称功能&#xff0c;所谓的智能对称就是当您在编辑其中一半的物体模型时&#xff0c;执行相关操作另一半模型会自动完成对…

HotSpot IO与NIO

Java NIO和IO之间第一个最大的区别是&#xff0c;IO是面向流的&#xff0c;NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节&#xff0c;直至读取所有字节&#xff0c;它们没有被缓存在任何地方。此外&#xff0c;它不能前后移动流中的数据。如果需要前后移…

Linux5.4内核编译

Linux是如此美妙&#xff0c;如此有趣。Like Matrix&#xff0c;It’s Everywhere ! 编译环境 Windows10, Vmware16, Ubuntu20.04&#xff0c;虚拟环境。PC机&#xff0c;内存32G&#xff0c;CPU 16 核心&#xff0c;I7八代。 源码下载 检查Ubuntu虚拟环境的内核版本&#…

Linux ELF文件

ELF全称&#xff1a;可执行链接格式&#xff0c;是UNIX系统实验室&#xff08;USL&#xff09;作为应用程序二进制接口&#xff08;Application Binary Interface&#xff0c;ABI&#xff09;而开发和发布的。ELF文件有三种不同类型&#xff1a; 可重定位文件&#xff1a;包含…

Linux内存分段分页

随着集成技术越来越精细&#xff0c;内存存储量从字节&#xff0c;千字节&#xff0c;兆字节&#xff0c;GB&#xff0c;…容量越来越大。如何有效地管理内存是一门艺术。在80X86体系中通过分段部件和分页部件提供内存管理的支持&#xff0c;由此从换分出实地址模式&#xff0c…

Linux内存域管理

Linux作为通用硬件内核&#xff0c;在内存管理上如何实现通用且高效。在前面Linux内存分段分页一篇我们主要讲解Linux内核进行物理地址逻辑地址线性地址的抽象映射&#xff0c;犹如在蛮荒之地为各家各户划分领土&#xff0c;像极了土地改革。考虑一个国家的土地治理过程&#x…