深入学习和认识class文件内部结构

简介: 深入学习和认识class文件内部结构

我们在学习java的时候总是会说java是一种跨平台性的语言,即一次编译,到处运行。但是为什么说java能够一次编译,导出运行呢?其实这主要还是需要依赖jvm,而JVM其实是不认识java文件的,因此当java程序被编译之后,会变成class文件,只要相应的class文件能够符合jvm的规范要求,那他们就能够被jvm所运行。因此现在除了java语言之外,kotlin,Scala,Clojure等语言都可以在jvm上运行。可以说,很多语言的出现都离不开JVM。那么对于class文件的基本结构,又该如何深入学习呢?


首先在本次学习class文件结构之前,我们需要先准备两个东西。


1.HelloWorld.java程序:


网络异常,图片无法展示
|


2.OoLong.jar。Oolong这是一种汇编语言的名称。首先我们需要到指定的github上边去下载资源。


github.com/jpbirdy/pro…




下载完毕之后,需要将相应的文件编译成class字节码,然后在用java命令将其打包成jar文件。


直接进入src目录底下,输入以下命令:


jar cvf OoLong.jar COM  
复制代码


(这里的COM文件夹底下的所有java程序都已经被编译成了class字节码)

然后COM目录底下的内容就会被自动打包成为一个叫做OoLang.jar的工具包了。


网络异常,图片无法展示
|


然后我们将该jar包放在需要测试的Helloworld.class字节码文件同级目录处。


java -verbose -cp OoLong.jar COM.sootNsmoke.oolong.Gnoloo HelloWorld.class

输入以上命令,即可进行转换:


网络异常,图片无法展示
|


转换完毕之后,大致如下图所示:


网络异常,图片无法展示
|


接着小编用Notepad++打开了HelloWorld.j文件,查看了里面的内容:


网络异常,图片无法展示
|


稍微来解释一下:


.source 指令是指程序的源文件

.class 表示这是一个类 并指定相应的类名

.super 表示这个类的父类是Object类型

.method public ()V 表示这是一个公有的方法 表示这是一个构造函数 V表示该函数的返回类型为void


好了,接下来我们将这个HelloWorld.java文件转换成二进制的字节码文件进行试验:

为了方便阅读和下边的讲解,我用了下边这个指令来进行测试:


java -verbose -cp OoLong.jar COM.sootNsmoke.oolong.DumpClass HelloWorld.class


文件被转成了二进制的字节码文件后,内容如下图所示:


(为了便于观察,小编在实验的时候使用了idea编辑器的终端窗口)


网络异常,图片无法展示
|


现在我们来对这段二进制文件作深入的分析。


首先是文件的头部信息:


1.魔数


网络异常,图片无法展示
|


这段头部信息也被称之为魔数。主要是用来标识该class文件的类型。通常都是以cafebabe这段十六进制的数字来表示。


2.Class文件的版本信息

接着魔数的下方,我们会发现这些内容:


网络异常,图片无法展示
|


这里的两个字节分别是表示相应的最大最小java版本范围。


总结起来就是从000000-000006的这6个字节分别表示了这个class文件的基本头部信息。

这些数字的作用主要是限制低版本jvm执行高版本的class文件。这也就是为什么有的时候,高版本jvm环境生成的class文件在移植到低版本jvm环境中无法执行的根本原因了。


3.常量池


接下来的这部分主要是描述常量池的内容:


网络异常,图片无法展示
|


这些东西被称之为常量池,常量池里面主要存放了两种类型的常量。


字面值常量(String字符串和final修饰的值)和符号引用(类名,接口名字,方法名称,字段名称等)


仔细观察会发现,每个常量都是由三个字节来进行描述的。基本结构如下:


网络异常,图片无法展示
|


jvm中定义了多种常量的类型,分别用数字来一一对应。


常量类型中包括了我们所熟知的一些Integer,String类型。


接下来我们通过解释几个不常见的常量类型来加深对于常量池的理解:


UTF8常量类型(有些书籍也称之为CONSTANT_Utf8_info)


网络异常,图片无法展示
|


在jvm的数字对应规则中,01表示的常量类型是utf8常量,这里的末尾数字6表示这个常量的长度为6。


在CONSTANT_Utf8_info常量类型里面,该常量的长度被限制为了2个字节,也就是64k,又由于class文件的接口,字段,方法名称,包名都是用这个常量类来表示的,因此类的全限定名、字段名、方法名的最大长度不能超过2个字节所能表示的最大整数,也就是65535。


Fieldref,Methodref常量类型


网络异常,图片无法展示
|


这种类型主要是用于描述class项里面的属性和方法。


Class常量类型


这种常量类型主要是用于描述该类的名称


网络异常,图片无法展示
|


4.访问标志


在常量池之后的部分,主要是一些描述类本身的相关信息内容。例如是否实现接口,是否为抽象类,属性个数,方法个数等。


网络异常,图片无法展示
|


5.Fields和Methods部分


这部分的内容主要是指程序本身的属性和方法的一些描述信息:


例如说一些本地栈的深度,常量的个数等信息,以及异常个数等信息:


网络异常,图片无法展示
|


6.class属性的描述


网络异常,图片无法展示
|


这里面主要是两个java语言的属性描述,sourcefile和name的描述。

目录
相关文章
|
7月前
|
JavaScript
js开发:请解释什么是ES6的类(class),并说明它与传统构造函数的区别。
ES6的类提供了一种更简洁的面向对象编程方式,对比传统的构造函数,具有更好的可读性和可维护性。类使用`class`定义,`constructor`定义构造方法,`extends`实现继承,并可直接定义静态方法。示例展示了如何创建`Person`类、`Student`子类以及它们的方法调用。
90 2
|
3月前
|
C++
2合1,整合C++类(Class)代码转换为MASM32代码的平台
2合1,整合C++类(Class)代码转换为MASM32代码的平台
|
7月前
|
编译器 C语言 C++
【C++专栏】C++入门 | 类和对象 | 类的引入、struct&class的区别、类的定义
【C++专栏】C++入门 | 类和对象 | 类的引入、struct&class的区别、类的定义
44 0
|
设计模式 JavaScript 前端开发
class 继承的重点
前文已提过:在 class 出现之前,JavaScript 实现继承是件麻烦事,构造函数继承有加上原型上的函数不能复用的问题;原型链继承又存在引用值属性的修改不独立的问题;组合继承又存在两次调用构造函数的问题,寄生组合继承,写起来又太麻烦了,总之,在 class 出现前,JavaScipt 实现继承真是件麻烦事儿。
|
存储 Java 程序员
深入理解Java中的三个修饰符(抽象(abstract)、静态(static)和最终的,不可变(final))【配视频】
🍅程序员小王的博客:程序员小王的博客 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕 🍅java自学的学习路线:java自学的学习路线
385 0
深入理解Java中的三个修饰符(抽象(abstract)、静态(static)和最终的,不可变(final))【配视频】
|
Java 索引
Class文件结构分析
Class文件结构分析 1. Class文件的结构概览图 2. 每一项数据说明 类型 名称 数量 说明 u4 magic 1 魔数:确定一个文件是否是Class文件 u2 minor_version
115 0
|
存储 XML Java
JVM虚拟机-Class文件简介
JVM虚拟机-Class文件简介
144 0
JVM虚拟机-Class文件简介
JVM虚拟机-Class文件之方法表集合
JVM虚拟机-Class文件之方法表集合
111 0
JVM虚拟机-Class文件之方法表集合
|
存储 XML Oracle
【JVM深度解析】Class文件结构
你了解Class文件结构吗?那你知道为什么会有魔数吗?定义的类变量会在什么地方出现呢?...不懂?一文带你了解Class文件结构。
【JVM深度解析】Class文件结构