JAVA虚拟机入门(1)---------类文件结构(上)

大家好,由于最近被动态加载的知识卡住,而动态加载涉及到java虚拟机中的加载机制,因此我决定花一定的时间来学习java虚拟机,特别是类加载部分,主要参照《深入理解java虚拟机》这本书进行学习,这本书的pdf版请前往链接获取。

http://download.csdn.net/detail/hollow12384/9606072

今天是java虚拟机的第一门课程,主要讲解的内容如下:

(1)java虚拟机的语言无关性

(2)Class文件结构概述

(3)解剖Class文件每个字节的含义

一:java虚拟机的语言无关性

java面世时就提出一个口号:”一次编写,到处运行“,这句话表明了java的目标是跨平台运行,这个目标最终怎么实现呢?自然是通过操作系统的

应用层实现,而实现的方式就是虚拟机了。只要不同平台的虚拟机和所有平台都使用统一的程序存储格式—–字节码格式,就能达到跨平台的目的。

这里就涉及到一个概念,什么是字节码格式?

字节码(英语:Bytecode)通常指的是已经经过编译,但与特定机器码无关,需要直译器转译后才能成为机器码的中间代码。字节码通常不像源码一样可以让人阅读,而是编码后的数值常量、引用、指令等构成的序列。

字节码主要为了实现特定软件运行和软件环境、与硬件环境无关。字节码的实现方式是通过编译器和虚拟机器。编译器将源码编译成字节码,特定平台上的虚拟机器将字节码转译为可以直接执行的指令。字节码的典型应用为Java bytecode。

通俗的说,字节码就是源码经过编译器后出来的东西。

字节码本质上就是二进制码。

不过,java的强大之处不止在于跨平台,java不仅具有平台无关性,而且具有很强的语言无关性。什么意思呢?

不管是什么语言,只要对应的编译器能够将程序代码编译成Class文件,java虚拟机并不在乎到底Class文件是由什么得来的,只要它符合Class文件结构的要求,就能在java虚拟机中运行。

二:Class文件结构概述

前面我们已经介绍了,java虚拟机运行的是Class文件,那么Class文件到底是什么呢?Class文件的结构又该符合什么要求呢?下面讲解的就是这个内容。

首先明确一点,Class文件是一组以8个字节为基础单位的二进制流。Class文件流中没有分割符,这使得Class文件储存的数据几乎都是有效的关键的数据。有人可能会问,如果储存的数据需要占用8个字节以上的空间怎么办呢?这个时候就按照高位在前的方式,分割成若干个8个字节进行储存。

那具体应该怎么储存呢?Class文件格式采用了类似于C语言结构体的伪结构进行储存。这种结构只有两种数据类型:无符号数和表。后面关于Class文件的结构解析都要建立在这两种数据类型上,因此先讲解这两种数据类型。

(一)无符号数

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

(二)表

表是由多个无符号数或其他表作为数据项构成的复合数据类型。所有的表都习惯性的用_info结尾,因此可以用这个来区分表和无符号数。整个Class本质上就是一张表,它由以下的数据项构成:

无论是无符号数还是表,如果需要描述同一个类型并且数据量不多,经常会使用一个前置的容量计数器加上若干个数据项的形式,这个时候称这一系列连续的某个类型的数据为某一类型的集合。

三:解剖Class文件每个字节的含义

第二点说明了Class文件采用无符号数和表来储存数据,但是具体怎么储存呢?储存的规则是什么呢?

在正式讲解之前,建议大家先下载安装一个软件WinHex,我们将使用这个软件来将.class字节码文件转化为16进制数进行解析。

接下来先对Class文件解析的规则进行解释:

整个.class文件转化为16进制后就是按照上述这张表进行解析。

接下来就耐心地对表里的每一项进行详细解释。

在解释之前,由于我比较倾向于用实例解释,因此我用一个实在的java项目生成的.class文件进行解析。

当然,这个java项目十分简单,只有一个类,

这个类位于这个包内:

到这个包所在的目录,打开bin,在里面就可以找到.class文件(注意,我们是对.class文件解析而不是.java文件,还记得吗?进入java虚拟机的是.class文件而不是.java文件)

然后用winHex打开这个.class文件,就可以看到.class文件的16进制表示了。

好了,做足了准备工作,就可以开始解析了。

ps:由于篇幅较长,因此我将这部分分为两篇博客,这篇博客讲解的前四个属性,剩余的属性见JAVA虚拟机入门(1)———-类文件结构(下)

(一)魔数(4个字节)

Class文件的前4个字节称为魔数,是用于确定这个文件是否是可以被java虚拟机接受的.class文件,为啥不用后缀名来判断呢?当然是因为

后缀名实在是太容易改了,而文件格式制定者只要采用标示文件格式的魔数,并且魔数没有被其他人采用,那就可以起到标示的作用了。Class文件的魔数是

CAFE BABE(咖啡宝贝),是否特别好记?看我们解析出来的16机制文件前四个字节,正是CAFE BABE!

(二)版本号(4个字节)

魔数后面紧跟着的就是版本号了,包括次版本号和主版本号,各占2个字节。在我们的例子中就是0000和0034,0000说明此版本号为0,0034说明主版本号为52,因此编译器jdk的版本就是52.0。

(三)常量池(不定个字节)

常量池是Class文件中出现的第一个表类型数据类型,而且占据着Class文件的最大空间,同时与其他项目的关联最多。因此,常量池是一个比较复杂并且重要的内容。

大家也可能注意到,在介绍常量池的时候,我用了“不定个字节”,说明常量池的字节长度是不确定的。那怎么确定常量池到底是到哪里呢?这取决于常量池

的前两个字节u2,在这个例子中也就是0016,这表示一共有21个常量,为什么不是22呢(0016的十进制表示就是22)?因为第一个字节是空出来

的,用于后面指向常量池的索引数据在特定情况下表达“不引用任何一个常量池项目”的意思,这种情况下将索引值置为0(也就是常量池第一个字节)就行了。

常量池中的常量主要包括两大类:Leteral和符号引用(Symbolic Reference)。Literal类似于java描述的常量,如文本字符串,final修饰的类型。符号引用主要包括三类常量:

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

(2)字段的名称和限定符

(3)方法的名称和限定符

关于类加载的知识在下节解析。

这里抛出一个问题:为什么要使用符号引用?

推荐阅读

回到对16进制.class文件的解析,常量池中的每一个常量都是一个表,一共有11种表结构,他们具有共同的特征,就是第一个字节(u1)表示的是这种表的类型,接下来的字节根据他们各自的类型进行解析。主要参考下面的表。

还是举我们的例子,第9个字节和第10个字节(0016)表示常量池一共有21个常量,第一个常量的标志位是07,根据上面的表得知为

CONSTANT_Class_Info(记得之前说过吗,以info结尾的一般就是表结构了),并且u2指定的是全限定名常量项的索引,在这个例子中

u2是0002,说明全限定名常量项在第二个常量中。第二个常量的tag是01,说明是CONSTANT_Utf8_info,u2是0011,说明

utf8字符串占据的字节数是17个字节,也就是从6A一直到下一行的74,这17个字节代表的就是全限定名常量的名字。这里就涉及到怎么翻译utf8缩

略编码了。

从“\u0001”到”\u007f”之间的字符用一个字节表示,”\u0080”到”\u07ff”用两个字节表示,从”\u0800”到”\uffff”用三个字节表示。

在WinHex中,当你选中这17个字节时,旁边会自动显示相应的图形,在这个例子中显示的是”javaLearning/test“,正是这个项目的完整名字!再接下去的解析也是一样的,就不多说了。

不过这里要重点说明一下,由于Class的方法,字段等都需要引用到01,也即是CONSTANT_Utf8_info,因此

CONSTANT_Utf8_info的数量直接决定了java中方法和字段的数量,CONSTANT_Utf8_info指明长度的是length字

段,长度为u2,也就是16个bit,共有65535种可能排序,因此方法数的瓶颈就是65535了!如果方法数超过了这个数,那么将导致无法编译。

(四)访问标志(2个字节)

常量池21个常量过后就是访问标志了,在这个例子中是在Offset为000000D0这一行的76 61过后的两个字节,也就是00 21。首先先来看访问标志都有什么,以及每个对应的16进制数是什么?

注意表中的每个属性不一定与其他属性相斥,比如ACC_PUBLIC和ACC_FINAL,一个类既可以声明为public,也可以同时声明为final,这个时候的标志值就是两者的或运算了(0001 | 0010)。

回归到我们的例子中,我们的例子只有声明了public,那是不是就是0001呢?请注意,ACC_SUPER说明了,jdk1.2以后编译出来的

类都会有这个标志,而根据前面我们读到的jdk版本号,肯定大于1.2,因此绝对是带有这个标志的。所以真正的标志位为0001 | 0020 =

0021,和我们读出来的结果相符合了。

好了,这就是类文件结构最基本的前面几个字节码了,感兴趣的各位可以看JAVA虚拟机入门(1)——-类文件结构(下)   

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

推荐阅读更多精彩内容