class类文件结构

概述

    记得在第一节计算机程序课上我的老师就讲过:“计算机只认识0和1,所以我们写的程序需要经过编译器翻译成由0和1构成的二进制格式才能由计算机执行。”然而,发展至今计算机仍然只能识别0和1,同样我们所写的Java程序,最终要编译成Class文件,再由虚拟机翻译成0和1执行。

关于虚拟机

    Java语言在刚刚诞生之时曾提出过一个非常著名的宣传口号:“一次编写,到处运行(Write Once,Run Anywhere)”。时至今日,商业机构和开源机构已经在Java语言之外发展出一大批在Java虚拟机之上运行的语言,入Clojure、Groovy、JRuby、Jython、Scala等。
    实现语言无关性的基础仍然是虚拟机和字节码存储格式。Java虚拟机不和包括Java在内的任何语言绑定,它只与“Class文件”这种特定的二进制文件格式所关联,Class文件中包含了Java虚拟机指令集和符号表以及若干其他辅助信息。
    如此看来,任何一门功能性语言都可以表示为一个能被Java虚拟机所接受的有效的Class文件。因此,有一些Java语言本身无法有效支持的特性,并不代表字节码本身无法有效支持,这也为其它语言实现一些有别于Java语言特性提供了基础。

Class类文件的结构

    既然了解了虚拟机可以允许符合规范的Class文件,那么我们就一起来了解下Class文件都有哪些特定的结构和规范。
    在这里笔者使用的是WinHex十六进制编辑器,打开Class文件就可以清晰的看到类文件详细内容,如下图所示:


Java Class文件的结构.jpg

    Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符,整个Class文件中存储的内容几乎全部是程序运行的必要数据。
    这里要先介绍两个概念:
    1、无符号数,属于基本数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串。
    2、表,是由多个无符号数或者其它表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个Class文件本质上就是一张表。

魔数

    每个Class文件的头4个字节成为魔数(Magic Number),它唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件,很多文件存储标准中都使用魔数来进行身份识别。
    Class文件的魔数值为:“0xCAFEBABE”,这个魔数值在Java还称做“Oak”语言的时候就已经确定下来了。

Class文件的版本

    紧接着魔数的4个字节存储的是Class文件的版本号:第5和第6个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)。

常量池

    紧接着主次版本号之后的是常量池入口,常量池可以理解为Class文件之中的资源仓库,他是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时它还是在Class文件中第一个出现的表类型数据项目。
    常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。字面量比较接近于Java语言层面的常量概念,如文本字符串、声明为final的常量值等。而符号引用则属于编译原理方面的概念,包括了下面三大类常量:
    1、类和接口的全限定名(Fully Qualified Name)。
    2、字段的名称和描述符(Descriptor)。
    3、方法的名称和描述符。

访问标志

    在常量池结束之后,紧接着的两个字节代表访问标志(access_flags),这个标志用于识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口;是否定义public类型;是否定义为abstract类型;

类索引、父类索引与接口索引集合

    类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类的集成关系。
    类索引、父类索引和接口索引集合都按顺序排列在访问标志之后,类索引和父类索引用两个u2类型的索引值表示,它们各自指向一个类型为CONSTANT_Class_info的类描述符常量,通过CONSTANT_Class_info类型的常量中的索引值可以找到定义在CONSTANT_Utf8_info类型的常量中的权限定名字符串。

字段表集合

    字段表(field_info)用于描述接口或者类中声明的变量。字段(field)包括类级变量以及实例级变量,但不包括在方法声明的局部变量。可以包括的信息有:字段的作用域(public、private、protected等)、实例变量还是类变量(static修饰符)、可变性(final)、并发可见性(volatile修饰符)、可否被序列化(transient修饰符)、字段数据类型(基本类型、对象、数组)、字段名称。
    字段集合中不会列出从超类或者父接口中继承而来的字段,但有可能列出原本Java代码之中不存在的字段,譬如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。
    这里正好举例说一下,Java语言不支持但Class文件支持的特性;在Java语言中字段是无法重载的,两个字段的数据类型、修饰符不管是否相同,都必须使用不一样的名称,但对于Class字节码来讲,如果两个字段的描述符不一样,那字段重名就是合法的。

方法表集合

    Class文件存储格式中对方法的描述与对字段的描述几乎采用了完全一致的方式,方法表的结构如同字段表一样,仅在访问标志和属性表集合的可选项中有所区别。

属性表集合

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

1、Code属性

    Java程序方法体中的代码经过Javac编译器处理后,最终变为字节码指令存储在Code属性内。

2、Exceptions属性

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

3、LineNumberTable属性

    LineNumberTable属性用于描述Java源码行号与字节码行号之间的对应关系,它并不是运行时必需的属性,但默认会生成到Class文件之中。

4、LocalVariableTable属性

    LocalVariableTable属性用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,它也不是必需属性。

5、SourceFile属性

    SourceFile属性用于记录生成这个Class文件的源码文件名称。这个属性也不是必需属性。

6、ConstantValue属性

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

7、InnerClasses属性

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

8、Deprecated及Synthetic属性

    Deprecated和Synthetic两个属性都属于标志类型的布尔属性,只存在有和没有的区别,没有属性值概念。其中Deprecated属性用于表示某个类、字段或者方法已经被程序作者定为不再推荐使用。Synthetic属性代表此字段或者方法并不是由Java源码直接产生的,而是由编译器自行添加的。

9、StackMapTable属性

    StackMapTable属性在JDK1.6发布后增加到Class文件规范中,它是一个复杂的变长属性,位于Code属性的属性表中。

10、Signature属性

    Signature属性在JDK1.5发布后增加到Class文件规范中,它是一个可选的定长属性,可以出现于类、字段表和方法表结构的属性表中。

11、BootstrapMethods属性

    BootstrapMethods属性在JDK1.7发布后增加到了Class文件规范之中,它是一个复杂的变长属性,位于类文件的属性表中。

总结

    今天为大家介绍了Class文件的结构,虽然看似没有用处,一些大公司的面试可能会问道Class文件的结构,当然答不出来并不会影响面试,但能答上来可以加分呀。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容