Class文件结构(七)

Class文件是平台无关性的基础之一

平台无关性和语言无关性。Java的一个非常著名的宣传口号:“一次编写,到处运行(Write Once,Run Anywhere)”。Sun公司以及其他虚拟机提供商发布了许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而实现了程序的“一次编写,到处运行”。各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(ByteCode)是构成平台无关性的基石。 同时语言无关性也越来越被开发者所重视。到目前为止大部分程序员还认为Java虚拟机执行Java程序是一件理所应当和天经地义的事情。时至今日,商业机构和开源机构已经在Java语言之外发展出一大批在Java虚拟机之上运行的语言,如Clojure,Groovy,JRuby,Jython,Scala等。实现语言无关性的基础仍然是虚拟机和字节码存储格式。Java虚拟机不和包括Java在内的任何语言绑定,他只与“Class文件”这种特定的二进制文件格式所关联,在满足Java虚拟机规范的要求下,任何一门功能性语言都可以表示为一个能被Java虚拟机所接受的有效的Class文件。例:除了Java语言,JRuby等同样可以通过编译器得到Class文件,虚拟机不关心Class文件的来源是何种语言

Class类文件结构:

Class文件是一组以8位字节为基础单元的二进制数据流。各个数据项目严格按照顺序紧凑的排列在Class文件之中。中间没有添加任何分隔符,这使得整个Class文件存储的内容几乎全部都是程序运行的必要数据。Class文件采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表无符号数属于基本的数据类型,以u1,u2,u4,u8来分别代表1个字节,2个字节,4个字节,8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照Utf-8编码构成字符串值。表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性的以“_info”结尾。如图:表中数据项无论是顺序还是数量,甚至于数据存储的字节序都是被严格限定的,不允许改变

示例代码:

public class TestClass {

    private int m;

    public int inc(){

        return m + 1;

    }

}

以下Class文件的字节码文件出自该代码片段。

Class结构数据项分析:(魔数、文件的版本号、次版本号、主版本号、常量池、访问标志

魔数:每个Class文件的头4个字节称为魔数(Magic Number),他的唯一作用是确定这个文件是否为能被虚拟机接受的Class文件。使用魔数而不是扩展名来进行识别主要基于安全方面的考虑(gif、jpeg等也使用),因为文件扩展名可以随意改动。值为:0xCAFEBABE(咖啡宝贝),紧接着魔数的4个字节存储的是Class文件的版本号,第5和第6个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)。Java的版本号是从45开始的,JDK1.1之后的每个JDK大版本发布主版本号向上加1(JDK1.0~1.1使用了45.0~45.1的版本号),高版本的JDK能向下兼容以前的版本的Class文件,但不能运行以后版本的Class文件,即使文件格式未发生任何变化,虚拟机也必须拒绝超过其版本号的Class文件。如图(winhex打开):地址为:0x00000007(33)。十六进制33转成十进制51代表JDK1.7。

常量池:紧接主版本号之后的是常量池的入口。常量池可以理解为Class文件之中的资源仓库。它是Class文件结构中与其他组成部分关联最多的数据类型,也是占用Class文件空间最大的数据部分之一,同时他还是在Class文件中第一个出现表类型数据的部分。由于常量池中常量数量不是固定的,所以在常量池的入口需要放置一项u2类型的数据代表常量池容量计数值(constant_pool_count)。常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。字面量比较接近于Java语言层面的常量概念,如文本字符串、声明final的常量值等。而符号引用则包括下面三类常量:

  1. 类和接口的全限定名(Fully Qualified Name)
  2. 字段的名称和描述符(Descriptor)
  3. 方法的名称和描述符

由于Java的“连接”步骤发生在类加载的时候,所以在Class文件中不会保存各个方法字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换的话无法得到真正的内存入口地址,也就无法直接被虚拟机使用。当虚拟机运行时需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中常量池中的每一项常量都是一个表(数据结构),这些表都有一个共同特点,即表开始的第一位是一个u1类型的标志位,代表当前常量属于哪种常量类型。其中每一种表(常量类型)都有自己的结构。如图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值