Java虚拟机:class类文件结构

一、平台无关性:

        Java的无关性的实现,是由Java源代码编译后生成的字节码class文件和Java虚拟机实现的。无关性包括:平台无关性以及语言无关性。

    (1)平台无关性,是指java代码可以运行在不同操作系统的虚拟机上面,因为不同的操作系统都有各自的Java虚拟机,从而实现程序的“一次编写,到处运行”。

    (2)语言无关性是指Java虚拟机能运行除Java以外的代码,JVM执行的是class文件,也就是JVM只认识class文件,它并不关心Class文件的来源是什么语言,只要它符合一定的结构,就可以在Java中运行。

 

二、类文件结构:

class文件是Java虚拟机执行引擎的数据入口,是一组以8位字节为基础单位的二进制流,存储的内容几乎都是程序运行的必要数据。

class文件的数据存储结构中只有两种数据类型:无符号数和表。class文件中的数据项,都被严格限定的,每个字节代表的含义,长度,先后顺序等都不允许改变。

(1)无符号数属于基本数据类型,以u1、u2、u4、u8来分别代表1、2、4、8个字节的无符号数。

(2)表是由多个无符号数或其他表作为数据项构成的复合数据类型。

class类文件的结构:

    1. 魔数

    2. 文件版本信息

    3. 常量池

    4. 访问标志

    5. 类索引、父类索引、接口索引集合

    6. 字段表集合

    7. 方法表集合

    8. 属性表集合

1、魔数:

        每个Class文件的头4个字节称为魔数(magic),它的唯一作用是判断该文件是否为一个能被虚拟机接受的Class文件。它的值固定为0xCAFEBABE。

2、文件版本信息:

        紧接着magic的4个字节存储的是Class文件的次版本号和主版本号,高版本的JDK能向下兼容低版本的Class文件,但不能运行更高版本的Class文件,即使该版本没有用到高版本JDK的特性。

3、常量池:

        紧接着版本号之后的就是常量池入口,它是class文件中的资源仓库。它是Class文件中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一。常量池中主要存放两大类常量:字面量和符号引用。

        字面量比较接近于Java层面的常量概念,如文本字符串、被声明为final的常量值等。

        而符号引用总结起来则包括了下面三类常量:

         (1)类和接口的全限定名

         (2)字段的名称和描述符

         (3)方法的名称和描述符

4、访问标志:

        在常量池结束之后,紧接着的2个字节代表访问标志(access_flag),这个标志用于识别一些类或接口层次的访问信息,包括:这个Class是类还是接口,是否定义为public类型,abstract类型,如果是类的话,是否声明为final,等。

5、类索引、父类索引、接口索引集合:

        Class文件中由这三项数据来确定这个类的继承关系。类索引、父类索引和接口索引集合都按照顺序排列在访问标志之后。类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。接口索引集合就用来描述这个类实现了哪些接口。

6、字段表集合:

        字段表(field_info)用于描述接口或类中声明的变量。字段包括了类级变量或实例级变量,但不包括在方法内声明的变量。可以包括的信息有:字段的作用域、是实例变量还是类变量、可变性、并发可见性、可否被序列化、字段数据类型、字段名称。但是,字段的名字、数据类型、修饰符等都是无法固定的,只能引用常量池中的常量来描述。

        字段表集合中不会列出从父类或接口中继承而来的字段,但有可能列出原本Java代码中不存在的字段。比如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。

7、方法表集合:

        方法表(method_info)的结构与字段表的结构相同。方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性表集合中一个名为“Code”的属性里。

        与字段表集合相对应,如果父类方法在子类中没有被覆写,方法表集合中就不会出现来自父类的方法信息。但同样,有可能会出现由编译器自动添加的方法,最典型的便是类构造器“<clinit>”方法和实例构造器“<init>”方法。

        重载一个方法需要有相同的简单名称和不同的特征签名。JVM的特征签名和Java的特征签名有所不同: 

        (1)Java特征签名:方法参数在常量池中的字段符号引用的集合

        (2)JVM特征签名:方法参数+返回值

8、属性表集合:

        属性表(attribute_info),在Class文件、字段表、方法表中都可以携带自己的属性表集合,以用于描述某些场景专有的信息。

(1)Code属性:

        Java程序方法体中的代码讲过Javac编译后,生成的字节码指令便会存储在Code属性中,但并非所有的方法表都必须存在这个属性,比如接口或抽象类中的方法就不存在Code属性。

        Code属性是Class文件中最重要的一个属性,如果把一个Java程序中的信息分为代码和元数据两部分,那么在整个Class文件里,Code属性用于描述代码,所有的其他数据项目都用于描述元数据。

(2)Exception属性:

        这里的Exception属性的作用是列举出方法中可能抛出的受查异常,也就是方法描述时在throws关键字后面列举的异常。

(3)LineNumberTable属性:

        它用于描述Java源码行号与字节码行号之间的对应关系。

(4)LocalVariableTable属性:

        它用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的对应关系。

(5)SourceFile属性:

        它用于记录生成这个Class文件的源码文件名称。

(6)ConstantValue属性:

        ConstantValue属性的作用是通知虚拟机自动为静态变量赋值,只有被static修饰的变量才可以使用这项属性。

        在Java中,对非static类型的变量(也就是实例变量)的赋值是在实例构造器<init>方法中进行的;而对于类变量(static变量),则有两种方式可以选择:在类构造其中赋值,或使用ConstantValue属性赋值。

        如果同时使用final和static修饰一个变量(即全局常量),并且这个变量的数据类型是基本类型或String的话,就生成ConstantValue属性来进行初始化,如果该变量没有被final修饰,或者并非基本类型及字符串,则选择在<clinit>方法中进行初始化。

(7)InnerClasses属性:

        该属性用于记录内部类与宿主类之间的关联。如果一个类中定义了内部类,那么编译器将会为它及它所包含的内部类生成InnerClasses属性。

(8)Deprecated属性:

        Deprecated该属性用于表示某个类、字段和方法,已经被程序作者定为不再推荐使用,它可以通过在代码中使用@Deprecated注释进行设置。

(9)Synthetic属性:

        该属性代表此字段或方法并不是Java源代码直接生成的,而是由编译器自行添加的,如this字段和实例构造器、类构造器等。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张维鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值