Java类文件结构

Java类文件结构

阅读目录

回到顶部

一、概述

  实现语言无关性的基础是虚拟机和字节码存储格式。Java虚拟机不和包括Java在内的任何语言绑定,只与"Class文件"这种特定的二进制文件所关联,Class文件中包含了Java虚拟机指令集合符号表以及若干其它辅助信息。Java虚拟机作为一个通用的、机器无关的执行平台,任何其他语言都可以将其作为语言的产品交付媒介。

  

回到顶部

二、Class类文件的结构

  Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件中,中间没有添加任何分隔符,使得整个Class文件中存储的内容几乎全部都是程序运行的必要数据,没有空隙存在。当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割若干个8位字节进行存储。

  根据Java虚拟机规范的规定,Class文件格式采用一种类似C语言结构体的伪结构来存储数据,这种伪结构只有两种数据类型:无符号数和表。

  无符号数:属于基本的数据类型,以u1、u2、u4、u8分别表示1个字节、2个字节、4个字节、8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值。

  :由多个无符号数和其他表作为数据项构成的复合类型的数据类型,所有的表都习惯地以"_info"结尾,表用于描述有层次关系的复合结构的数据,整个Class文件本质上就是一张表。,它由下表所示的数据项构成:

  

  下面看看表中各个数据项的具体含义:

  1、魔数和Class文件的版本

  每个Class文件的头四个字节称为魔数,它的唯一作用就是确定这个文件是否为一个能被虚拟机接受的Class文件。很多文件存储标准都是使用魔数而不是扩展名来进行识别,主要是基于安全方面考虑。紧接着魔数的四个字节存储的是Class文件的版本号:第五和第六是此版本号,第七和第八是主版本号,以下面的类为例:

public class TestClass
{
    private String m;
    public String test()
    {
        return m;
    }
}

  查看生成的class文件:

  

  可以看到代表次版本号的第五个和第六个字节为0x0000,主版本号为0x0032,也就是十进制的50。

  2、常量池

  紧接着主版本号之后是常量池入口,常量池可以理解为Class文件之中的资源仓库,它是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时还是在Class文件中第一个出现的表类型数据项目。由于常量池中常量的数量不是固定的,所以在常量池的入口需要放置一项u2类型的数据u,代表常量池容量计数值,这个容量技术值是从1开始而不是从0开始的。这样做的目的在于满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项目”的含义,这种情况就可以把索引值置为0来表示。上图中常量池容量为0x0016,即十进制中的22,这就表示常量池中有21项常量。

  常量池中主要存放两大类常量:字面量和符号引用。

  字面量近似于Java的常量,如文本字符串、声明为final的常量值,而符号引用则属于编译原理方面的概念,包括:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。

  Java代码在编译时没有连接的步骤,而是在虚拟机加载Class文件的时候进行动态连接。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。

  常量池的每一项常量都是一个表,在JDK 1.7共有14种结构各不相同的表结构数据。这些表有一个共同的特点,就是表开始的第一位是一个u1类型的标志位。

  回头看上面的表,常量池的第一项常量,它的标志位是0x07,属于CONSTANT_Class_info类型,此类型的常量代表一个类或者接口的符号引用。

  在JDK的bin目录中,有一个专门用于分析Class文件字节码的工具:javap,上述代码生成的Class文件使用javap工具的-verbose参数输出如下:

  

  可见,计算机已经帮我们把整个常量池的21项常量都计算出来了。

  3、访问标志

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

  4、类索引、父类索引和接口索引

  类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的集合,Class文件中的这个三个数据爱确定类的继承关系。类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。由于Java语言不允许多重继续,所以父类索引只有一个。接口索引集合就用来描述这个类实现了哪些接口,这些被实现的接口将按照Implements语句后的接口顺序从左到右排列在索引集合中。

  5、字段表集合

  字段表用于描述接口或类中声明的变量。字段包括类级变量以及实例变量,但不包括在方法内部声明的局部变量。可以包括的信息有:字段的作用域、是实例变量还是类变量(static 修饰符)、可变性(final)、并发可见性(volatile修饰)、是否可被序列化(transient修饰符)、字段数据类型、字段名称。上述的这些信息,各个修饰符都是布尔值。

  6、方法表集合

  方法表用于描述方法,包括的信息有:访问标志、名称索引、描述符索引、属性表集合等。方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性表集合中一个名为Code的属性里,属性表是Class文件格式中最具扩展性的一中数据项目。

  在Java语言中,要重载(Overload)一个方法,除了要与原方法具有相同的简单名称之外,还要求必须拥有一个与原方法不同的特征签名(特征签名就是一个方法中各个参数在常量池中的字段符号引用的集合),Java代码的方法特征签名只包括了方法名称、参数顺序以及参数类型,也就是因为返回值不包含在特征签名中,因此Java语言无法仅仅依靠返回值的不同来对一个已有方法进行重载。

  7、属性表集合

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

  Code属性:Java程序方法体中的代码经过Javac编译器处理后,最终变为字节码指令存储在Code属性内。Code属性出现在方法表的属性集合中,但是并非所有的方法表都必须存在这个属性,例如接口或者抽象类中的方法就不存在Code属性。

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

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

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

回到顶部

三、字节码指令

  Java虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码)以及跟随其后的零至多个代表操作所需参数而构成。由于Java虚拟机采用面向操作数栈而不是寄存器架构,所以大多数的指令都不包含操作数,只有一个操作码。由于限制了Java虚拟机操作码的长度为一个字节,这意味着指令集的操作码总数不可能超过256条。

  1、字节码与数据类型

  对于大部分与数据类型相关的字节码指令,它们的操作码助记符中都有特殊的字符来表示专门为哪种数据类型服务:i代表队int类型的数据操作,l代表long,s代表short,b代表byte,c代表char,f代表float,d代表double,a代表reference。也有一些指令助记符没有明确的指明操作类型的字母。还有一些指令与数据类型无关。Java虚拟机的指令集对于特殊的操作只提供了有限的类型相关指令去支持它,指令集被设计成非完全独立的,有一些单独的指令可以在必要的时候用来将一些不支持的类型转换为可被支持的类型。

  2、加载和存储指令

  加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输。

  3、运算指令

  运算或算术指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。

  4、类型转换指令

  类型转换指令可以将两种不同的数值类型进行相互转换,这些转换操作一般用于实现用户代码中的显示类型转换操作,或者用来处理上面提到的字节码指令集中数据类型相关指令无法与数据类型一一对应的问题。

  Java虚拟机直接支持以下数值类型的宽化类型转换(小范围类型向大范围类型的安全转换):

  • int类型到long、float或者double类型
  • long类型到float、double类型
  • float类型到double类型

  处理窄化类型转换时,则必须显式地使用转换指令来完成。

  5、异常处理命令

  在Java程序中显示抛出异常的操作都由athrow指令来实现,除了用throw语句显示抛出异常之外,Java虚拟机规范还规定了许多运行时异常会在其他Java虚拟机指令检测到异常状况时自动抛出。

  在Java虚拟机中,处理异常(catch语句)不是由字节码指令来实现的,才是采用异常表来完成的。

时间: 2024-08-07 12:24:33

Java类文件结构的相关文章

java类文件结构(字节码文件)

[0]README 0.1)本文部分文字描述转自 "深入理解jvm",旨在学习类文件结构  的基础知识: 0.2)本文荔枝以及荔枝的分析均为原创: 0.3)下面的截图中有附注t*编号,不关乎博文内容: [1]类文件概述 1)各种不同平台的虚拟机与所有平台都统一使用存储格式--字节码,他是构成平台无关性的基石: 2)时至今日,商业机构和开源机构已经在 java语言外发展出一大批在 jvm 上运行的语言,如 Groovy, JRuby, Jython,Scala等: 3)实现语言无关性的基

不知道Java类文件结构的同学,看这篇文章就够了

一.前言 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步.经过多年的发展,目前的计算机仍然只能识别0和1,但是由于近10年内虚拟机以及大量建立在虚拟机之上的程序语言如雨后春笋般出现并蓬勃发展,将我们编写的程序编译成二进制本地机器码(Native Code)已不再是唯一的选择,越来越多的程序语言选择了操作系统和机器指令集无关的.平台中立的格式作为程序编译后的存储格式. 二.class类文件结构 Class文件是一组以8位字节为基础单位的二进制流,各项数据严

java类文件结构笔记

我们都知道java实现跨平台靠的是虚拟机技术,将源文件编译成与操作系统无关的,只有虚拟机能识别并执行的字节码文件,由各个操作系统上的jvm来负责执行,屏蔽了底层具体的操作系统.这里我们就来认识一下这个只有jvm才认识的字节码文件的真实样子. 为了节省空间,类文件中没有任何分隔符,各个数据项都是一个挨着一个紧凑排列的,所以其中无论是顺序还是数量等都是严格规定的,哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变.下面我们先看一下类文件的整体结构: Class文件结构 其中常量.接口.字段

Java类文件结构及javac的ClassReader类解读

首先来看一下ClassFile,类注释如下: A JVM class file. Generic Java classfiles have one additional attribute for classes, methods and fields: "Signature" (u4 attr-length, u2 signature-index) A signature gives the full Java type of a method or field. When used

java 类文件结构

1  Class文件与虚拟机: Java 虚拟机不和包括Java 在内的任何语言绑定,它只与"Class文件"这种特定的二进制文件格式所关联,Class文件包含了Java虚拟机指令集和符号表以及若干其他辅助信息.基于安全方面的考虑,Java 虚拟机规范要求Class文件中使用许多强制性的语法和结构化约束,但任何一门语言都可以表示为一个能被Java虚拟机所接受的有效的Class文件.Java虚拟机不用关心Class的来源为何种语言 2 Class文件的结构 Class文件是一组以8位字节

java 类文件类型

我们所看到的Java字节码是被封装在一个类文件中(扩展名为.class).在这个教程中,就让我们来看看类文件的内部构造. 数据是如何被写入类文件以及类文件的格式是怎样的呢,让我们首先图解看一看Java类文件. Java类文件结构示意图:  上图描绘的Java类文件被分为了不同的区段,包括魔术码(magic).版本(version).常量池(constant pool).访问标识(access flags).(this)类.(super)类.接口(interfaces).域(fields).方法(

Java虚拟机 - Class类文件结构

[深入Java虚拟机]之二:Class类文件结构 平台无关性 Java是与平台无关的语言,这得益于Java源代码编译后生成的存储字节码的文件,即Class文件,以及Java虚拟机的实现.不仅使用Java编译器可以把Java代码编译成存储字节码的Class文件,使用JRuby等其他语言的编译器也可以把程序代码编译成Class文件,虚拟机并不关心Class的来源是什么语言,只要它符合一定的结构,就可以在Java中运行.Java语言中的各种变量.关键字和运算符的语义最终都是由多条字节码命令组合而成的,

深入了解Java虚拟机(3)类文件结构

虚拟机执行子系统 一.类文件结构 1.魔数和class版本 1.magic-魔数:0xCAFEBABE:4字节 2.minor_version:次版本,丶之后的数字:2字节 3.major_version:主版本,丶之前的数字:2字节 2.常量池 1.constant_pool_count:常量池常量数量(= 此值 - 1):2字节 由于常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值. 2.constant_pool:常量,第一位为类型位,之后的

(转)《深入理解java虚拟机》学习笔记5——Java Class类文件结构

Java语言从诞生之时就宣称一次编写,到处运行的跨平台特性,其实现原理是源码文件并没有直接编译成机器指令,而是编译成Java虚拟机可以识别和运行的字节码文件(Class类文件,*.class),字节码文件是一种平台无关的中间编译结果,字节码文件由java虚拟机读取,解析和执行,java虚拟机屏蔽了不同操作系统和硬件平台的差异性. 如今的java虚拟机已经称为一种通用平台,不但能够运行java语言,Groovy,JRuby,Jython等一大批动态语言也可以直接在Java虚拟机上运行,其原理也是这