设为首页 加入收藏

TOP

从 HelloWorld 看 Java 字节码文件结构(一)
2018-03-18 16:21:26 】 浏览:323
Tags:HelloWorld Java 字节 文件 结构

很多时候,我们都是从代码层面去学习如何编程,却很少去看看一个个 Java 代码背后到底是什么。今天就让我们从一个最简单的 Hello World 开始看一看 Java 的类文件结构。


在开始之前,我们先写一个最简单的入门 Hello World。


public class Demo{
    public static void main(String args[]){
        System.out.println("Hello World.");
  }
}


接着在命令行运行javac Demo.java命令编译这个类,这时会生成一个 Demo.class 文件。


接着我们用纯文本编辑器打开生成的 Demo.class 文件。


cafe babe 0000 0034 001d 0a00 0600 0f09
0010 0011 0800 120a 0013 0014 0700 1507
0016 0100 063c 696e 6974 3e01 0003 2829
5601 0004 436f 6465 0100 0f4c 696e 654e
756d 6265 7254 6162 6c65 0100 046d 6169
6e01 0016 285b 4c6a 6176 612f 6c61 6e67
2f53 7472 696e 673b 2956 0100 0a53 6f75
7263 6546 696c 6501 0009 4465 6d6f 2e6a
6176 610c 0007 0008 0700 170c 0018 0019
0100 0b48 656c 6c6f 2057 6f72 6c64 0700
1a0c 001b 001c 0100 0444 656d 6f01 0010
6a61 7661 2f6c 616e 672f 4f62 6a65 6374
0100 106a 6176 612f 6c61 6e67 2f53 7973
7465 6d01 0003 6f75 7401 0015 4c6a 6176
612f 696f 2f50 7269 6e74 5374 7265 616d
3b01 0013 6a61 7661 2f69 6f2f 5072 696e
7453 7472 6561 6d01 0007 7072 696e 746c
6e01 0015 284c 6a61 7661 2f6c 616e 672f
5374 7269 6e67 3b29 5600 2100 0500 0600
0000 0000 0200 0100 0700 0800 0100 0900
0000 1d00 0100 0100 0000 052a b700 01b1
0000 0001 000a 0000 0006 0001 0000 0001
0009 000b 000c 0001 0009 0000 0025 0002
0001 0000 0009 b200 0212 03b6 0004 b100
0000 0100 0a00 0000 0a00 0200 0000 0300
0800 0400 0100 0d00 0000 0200 0e


可以看到我们简单的 5 行代码到最后就浓缩成了上面那一长串数字字母组成的十六进制符号。而当我们运行该 Java 类时,控制台能准确地输出「Hello World」,所以们可以断定这一长串的符号必定遵守着某种规则,而这个规则其实就是:Java虚拟机规范


Java 虚拟机规范中规定了 Java 虚拟机结构、Class 类文件结构、字节码指令等内容,其中对于软件开发人员来说,类文件结构是有必要了解的一个内容。


Java 虚拟机的类文件结构是一组以 8 位字节为基础的二进制流,各数据项目严格按照顺序紧凑地排列在 Class 文件之中,中间没有添加任何分隔符,这使得整个 Class 文件中存储的内容几乎全都是程序需要的数据,没有空隙存在。


说完了 Java 虚拟机规范,就需要了解一下 Java 虚拟机这个概念。


其实 Java 虚拟机就是一个虚拟的计算机。与真实的计算机一样,Java 虚拟机有自己完善的硬件体系,如处理器、堆栈、寄存器,还有相应的指令集系统。虚拟机与我们的电脑唯一的区别是:虚拟机的处理器、内存堆栈是用软件虚拟出来的,而我们电脑的处理器和内存则是真真实实的。


虽然名字是叫 Java 虚拟机,但 Java 虚拟机与 Java 语言没有直接关系,它只按照 Java 虚拟机规范去读取 Class 文件,并按照规定去解析、执行字节码指令,仅此而已。


如果你够牛逼,你完全可以写一个编译器,将 C 语言代码编译成符合 Java 虚拟机规范的字节码文件,那么 Java 虚拟机也是可以执行的。


准确地说,Java 虚拟机与字节码文件(Class文件)绑定。


Java 虚拟机规范中定义了许多规范,其中有一部分定义了字节码的结构和规范。Java 虚拟机规范定义了两种数据类型来表示 Class 文件格式,分别是:无符号数和表。


无符号数属于最基本的数据类型,以 u1、u2、u4、u8 六七分别代表 1 个字节、2 个字节、4 个字节、8 个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8 编码构成的字符串值。例如下表中第一行中的 u4 表示 Class 文件前 4 个字节表示该文件的魔数,第二行的 u2 表示该 Class 文件第 5-6 个字节表示该 JDK 的次版本号。


是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾,表用于描述有层次关系的复合结构的数据。例如下表第 5 行表示其实一个类型为 cp_info 的表(常量池),这里面存储了该类的所有常量。
整个 Class 文件本质上就是一张表,它由表下表所示的数据项构成。



上面的表其实可以划分为以下七个部分,这七个部分组成了一个完整的 Class 字节码文件:


Class 文件的第 1 - 4 个字节代表了该文件的魔数(Magic Number)。它唯一的作用是确定这个文件是否为一个能被虚拟机接受的 Class 文件,其值固定是:0xCAFEBABE(咖啡宝贝)。如果一个 Class 文件的魔数不是 0xCAFEBABE,那么虚拟机将拒绝运行这个文件。


Class 文件的第 5 - 6 个字节代表了 Class 文件的次版本号(Minor Version),即编译该 Class 文件的 JDK 次版本号。


Class 文件的第 7 - 8 个字节代表了 Class 文件的主版本号(Major Version),即编译该 Class 文件的 JDK 主版本号。


高版本的 JDK 能向下兼容以前笨笨的 Class 文件,但不能运行新版本的 Class 文件。例如一个 Class 文件是使用 JDK 1.5 编译的,那么我们可以用 JDK 1.7 虚拟机运行它,但不能用 JDK 1.4 虚拟机运行它。下表列出了各个版本 JDK 的十六进制版本号信息:



我们看看之前的 Demo 文件的 Class 文件,其前 8 个字节分别是:cafe babe 0000 0034。那么我们可以知道,这个 Class 文件是由 JDK1.8 编译的。


Class 文件的第 9 - 10 个字节用于表示常量池常量的个数(constant_pool_count),那么紧跟着就有 constant_pool_count - 1 个常量。我们Class 文件第 9 - 10 个字节为 001d,表示有 28 个常量。


每个常量池的常量都用一个类型为 cp_info 的表表示,该表有 14 个值,分别是:



第 1 个常量。紧接着 001d 的后一个字节为 0A,表示该常量为方法引用类型(CONSTANT_MethodHandle_info)的常量。从上面的总表查阅知道,该常量项第 2 - 3 个字节表示类信息,这里是 0006 表示指向常量池第 6 个常量所表示的信息。该常量项的第 4 - 5 个字节表示名称及类描述符,这里值为 0

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇30行Python代码实现人脸检测 下一篇排查Java的内存问题

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目