性格测试
性格测试

您现在的位置: 性格测试_性格测试题目 > 性格测试题目 > Java反射在JVM的实现

Java反射在JVM的实现

发布时间:2017-9-27 19:37:38   点击数:

本文目录

什么是Java反射,有什么用?

JavaClass文件的结构

JavaClass加载的过程

反射在native的实现

附录

1.什么是Java反射,有什么用?

反射使程序代码能够接入装载到JVM中的类的内部信息,允许在编写与执行时,而不是源代码中选定的类协作的代码,是以开发效率换运行效率的一种手段。这使反射成为构建灵活应用的主要工具。

反射可以:

调用一些私有方法,实现黑科技。比如双卡短信发送、设置状态栏颜色、自动挂电话等。

实现序列化与反序列化,比如PO的ORM,Json解析等。

实现跨平台兼容,比如JDK中的SocketImpl的实现

通过xml或注解,实现依赖注入(DI),注解处理,动态代理,单元测试等功能。比如Retrofit、Spring或者Dagger

2.JavaClass文件的结构

在*.class文件中,以Byte流的形式进行Class的存储,通过一系列Load,Parse后,Java代码实际上可以映射为下图的结构体,这里可以用javap命令或者IDE插件进行查看。

typedefstruct{

u4magic;/*0xCAFEBABE*/

u2minor_version;/*网上有表可查*/

u2major_version;/*网上有表可查*/

u2constant_pool_count;

cp_infoconstant_pool[constant_pool_count-1];

u2access_flags;

u2this_class;

u2super_class;

u2interfaces_count;

u2interfaces[interfaces_count];

//重要

u2fields_count;

field_infofields[fields_count];

//重要

u2methods_count;

method_infomethods[methods_count];

u2attributes_count;

attribute_infoattributes[attributes_count];

}ClassBlock;

常量池(constantpool):类似于C中的DATA段与BSS段,提供常量、字符串、方法名等值或者符号(可以看作偏移定值的指针)的存放

access_flags:对Class的flag修饰

typedefenum{

ACC_PUBLIC=0x,

ACC_FINAL=0x,

ACC_SUPER=0x,

ACC_INTERFACE=0x,

ACC_ACSTRACT=0x

}AccessFlag

thisclass/superclass/interface:一个长度为u2的指针,指向常量池中真正的地址,将在Link阶段进行符号解引。

filed:字段信息,结构体如下

typedefstructfieldblock{

char*name;

char*type;

char*signature;

u2access_flags;

u2constant;

union{

union{

chardata[8];

uintptr_tu;

longlongl;

void*p;

inti;

}static_value;

u4offset;

}u;

}FieldBlock;

method:提供descriptor,access_flags,Code等索引,并指向常量池:

它的结构体如下,详细在这里

method_info{

u2access_flags;

u2name_index;

//theparametersthatthemethodtakesandthe

//valuethatitreturn

u2descriptor_index;

u2attributes_count;

attribute_infoattributes[attributes_count];

}

以上具体内容可以参考

JVM文档

周志明的《深入理解Java虚拟机》,少见的国内精品书籍

一些国外教程的解析

3.JavaClass加载的过程

Class的加载主要分为两步

第一步通过ClassLoader进行读取、连结操作

第二步进行Class的clinit()初始化。

3.1.Classloader加载过程

ClassLoader用于加载、连接、缓存Class,可以通过纯Java或者native进行实现。在JVM的native代码中,ClassLoader内部维护着一个线程安全的HashTableString,Class,用于实现对Class字节流解码后的缓存,如果HashTable中已经有了缓存,则直接返回缓存;反之,在获得类名后,通过读取文件、网络上的class字节流反序列化为JVM中native的C结构体,接着malloc内存,并将指针缓存在HashTable中。

下面是非数组情况下ClassLoader的流程

find/load:将文件反序列化为C结构体。

link:根据Class结构体常量池进行符号的解引。比如对象计算内存空间,创建方法表,nativeinvoker,接口方法表,finalizer函数等工作。

3.2.初始化过程

当ClassLoader加载Class结束后,将进行Class的初始化操作。主要执行clinit()的静态代码段与静态变量(取决于源码顺序)。

publicclassSample{

//step.1

staticintb=2;

//step.2

static{

b=3;

}

publicstaticvoidmain(String[]args){

Samples=newSample();

System.out.println(s.b);

//b=3

}

}

具体参考如下:

WhenandhowaJavaclassisloadedandinitialized?

TheLifetimeofaType

在完成初始化后,就是Object的构造init了,本文暂不讨论。

4.反射在native的实现

反射在Java中可以直接调用,不过最终调用的仍是native方法,以下为主流反射操作的实现。

4.1.Class.forName的实现

Class.forName可以通过包名寻找Class对象,比如Class.forName("java.lang.String")。

在JDK的源码实现中,可以发现最终调用的是native方法forName0(),它在JVM中调用的实际是findClassFromClassLoader(),原理与ClassLoader的流程一样,具体实现已经在上面介绍过了。

4.2.getDeclaredFields的实现

在JDK源码中,可以知道class.getDeclaredFields()方法实际调用的是native方法getDeclaredFields0(),它在JVM主要实现步骤如下

根据Class结构体信息,获取field_count与fields[]字段,这个字段早已在load过程中被放入了

根据field_count的大小分配内存、创建数组

将数组进行forEach循环,通过fields[]中的信息依次创建Object对象

返回数组指针

主要慢在如下方面

创建、计算、分配数组对象

对字段进行循环赋值

4.3.Method.invoke的实现

以下为无同步、无异常的情况下调用的步骤

创建Frame

如果对象flag为native,交给native_handler进行处理

在frame中执行java代码

弹出Frame

返回执行结果的指针

主要慢在如下方面

需要完全执行ByteCode而缺少JIT等优化

检查参数非常多,这些本来可以在编译器或者加载时完成

4.4.class.newInstance的实现

检测权限、预分配空间大小等参数

创建Object对象,并分配空间

通过Method.invoke调用构造函数(init())

返回Object指针

主要慢在如下方面

参数检查不能优化或者遗漏

init()的查表

Method.invoke本身耗时

5.附录

5.1.JVM与源码阅读工具的选择

初次学习JVM时,不建议去看AndroidArt、Hotspot等重量级JVM的实现,它内部的防御代码很多,还有android与libcore、bionic库紧密耦合,以及分层、内联甚至能把编译器的语义分析绕进去,因此找一个教学用的、嵌入式小型的JVM有利于节约自己的时间。因为以前折腾过OpenWrt,听过有大神推荐过jamvm,只有不到个源文件,非常适合学习。

在工具的选择上,个人推荐SourceInsight。对比了好几个工具clion,vscode,sublime,sourceinsight,只有sourceinsight对索引、符号表的解析最准确。

5.2.关于几个ClassLoader

参考这里

ClassLoader0:native的classloader,在JVM中用C写的,用于加载rt.jar的包,在Java中为空引用。

ExtClassLoader:用于加载JDK中额外的包,一般不怎么用

AppClassLoader:加载自己写的或者引用的第三方包,这个最常见

例子如下

//sun.misc.Launcher$AppClassLoader

4b67cf4d

//whichclassyoucreateorjarsfromthirdParty

//第一个非常有歧义,但是它的确是AppClassLoader

ClassLoader.getSystemClassLoader();









































北京看白癜风哪间医院专业
在北京治疗白癜风哪个医院最好


转载请注明:http://www.oliodemarte1850.com/xgtm/7068.html

网站简介 | 发布优势 | 服务条款 | 隐私保护 | 广告合作 | 合作伙伴 | 版权申明 | 网站地图

当前时间: