详解.class文件
话不多说,直接上图
.class文件理解:
-
在 Java 中,JVM 可以理解的代码就叫做
字节码
(即扩展名为.class
的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题并且保留了解释型语言可移植的特点,而通过即时编译器(jit)又有编译型语言执行效率高的特点。所以 Java 程序运行时比较高效。Java通过字节码文件和虚拟机jvm之间的关系,做到了平台无关性,一次编译,各平台都可运行。 -
补充Clojure(Lisp 语言的一种方言)、Groovy、Scala 等语言都是运行在 Java 虚拟机之上。下图展示了不同的语言被不同的编译器编译成
.class
文件最终运行在 Java 虚拟机之上。.class
文件的二进制格式可以使用 WinHex 查看 -
为什么说java是编译与解释共存
-
JIT即时编译器
class文件结构
- 根据 Java 虚拟机规范,Class 文件通过
ClassFile
定义,有点类似 C 语言的结构体。
魔数
每个Class文件的头4个字节被称为魔数(Magic Number) , 它的唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件。Class文件的魔数取得很有“浪漫气息”,
值为0xCAFEBABE(咖啡宝贝? )
紧接着魔数的4个字节存储的是Class文件的版本号: 第5和第6个字节是次版本号(MinorVersion) , 第7和第8个字节是主版本号(Major Version)
这里我们使用一个简单的代码进行分析:
public class TestClass {
private int m;
public int inc() {
return m + 1;
}
}
使用javac命令对其进行编译,并使用WinHex (下载地址:http://www.x-ways.net/winhex/index-m.html)工具打开,得到如下的图,前面几位就是魔数和版本号
这里可以得出我们使用的版本为java1.8,16进制的34等于10进制的52
常量池
紧接着主、 次版本号之后的是常量池入口, 常量池可以比喻为Class文件里的资源仓库, 它是Class文件结构中与其他项目关联最多的数据, 通常也是占用Class文件空间最大的数据项目之一。
常量池中主要存放两大类常量: 字面量(Literal) 和符号引用(Symbolic References) 。
常量池的入口需要放置一项u2类型的数据, 代表常量池容量计数值(constant_pool_count) ,这个容量计数是从1开始的。如下图所示:常量池容量(偏移地址: 0x00000008) 为十六进制数0x0013,则十进制为19,由于0(0算一个值)空出来,则这里有18个长常量索引范围为1-18,在Class文件格式规范制定之时, 设计者将第0项常量空出来是有特殊考虑的, 这样做的目的在于, 如果后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项目”的含义, 可以把索引值设置为0来表示。
然后我们使用javap命令查看该class文件:(这里明显显示为18个常量)
常量池中主要存放两大类常量: 字面量(Literal) 和符号引用(Symbolic References) 。
字面量比较接近于Java语言层面的常量概念, 如文本字符串、 被声明为final的常量值等。
符号引用则属于编译原理方面的概念, 主要包括下面几类常量:
- 被模块导出或者开