当前位置: 美高梅集团手机版 > 美高梅集团 > 正文

无符号数属于基本的数据类型,分割成若干个8位

时间:2019-10-07 05:04来源:美高梅集团
Class文件时一组以8位字节为基础单位的二进制流,当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个*位字节进行存储。Class文件格式采用一种类似C语

Class文件时一组以8位字节为基础单位的二进制流,当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个*位字节进行存储。Class文件格式采用一种类似C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。

1 什么是JVM的“无关性”?

Java具有平台无关性,也就是任何操作系统都能运行Java代码.之所以能实现这一点,是因为Java运行在虚拟机之上,不同的操作系统都拥有各自的Java虚拟机,因此Java能实现"一次编写,处处运行".

而JVM不仅具有平台无关性,还具有语言无关性.

  • 平台无关性是指不同操作系统都有各自的JVM
  • 语言无关性是指Java虚拟机能运行除Java以外的代码!

这听起来非常惊人,但JVM对能运行的语言是有严格要求的.首先来了解下Java代码的运行过程.

Java源代码首先需要使用Javac编译器编译成class文件,然后启动JVM执行class文件,从而程序开始运行.
也就是JVM只认识class文件,它并不管何种语言生成了class文件,只要class文件符合JVM的规范就能运行.
因此目前已经有Scala、JRuby、Jython等语言能够在JVM上运行.它们有各自的语法规则,不过它们的编译器都能将各自的源码编译成符合JVM规范的class文件,从而能够借助JVM运行它们.

这里写图片描述

jvm理论-class文件,jvm理论-class

当JVM运行Java程序的时候,它会加载对应的class文件,并提取class文件中的信息存放在JVM的方法区内存中。

Class文件组成

1、Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按顺序紧凑排列在Class文件中,中间没有分隔符。所以Class文件中存储的内容几乎全部是程序运行的必要数据。

2、当遇到占据8位字节以上空间的数据项时,会按照高位在前的方式, 分割成若干个8位字节进行存储。

Class文件数据类型

无符号数

1、基本数据类型,以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节。

2、无符号数可以用来描述数字、索引引用、数量值和按照UTF8编码构成字符串值。

1、表用来描述有层次关系的的复合数据结构。

2、表是由无符号数或者其他表作为数据项构成的复合数据结构。

3、所有表都以_info结尾。

4、整个class文件本质上就是一张表。

澳门美高梅游戏 1

item1:magic(魔数)[u4]:0xCAFEBABE

辨别class文件与非class文件

**item2:minor_version、major_version(次、主版本号) [u2,u2]**

随着Java技术的发展,class文件的格式会发生变化。版本号的作用在于使得虚拟机能够认识当前加载class的文件格式。从而准确的提取class文件信息。

澳门美高梅游戏 2

**item3:常量池(constant_pool_count 、constance_pool)[u2,cp_info]**

常量池内容

常量池存放两大类常量:字面量(Literal)和符号引用(Synbolic Reference)

一、字面量

1、文本字符串

2、声明为final的常量值

final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量

3、基本数据类型

4、其他

二、符号引用

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

常量池结构

JVM会将每一个常量构成一个常量表,每个常量表都有自己的入口地址。而实际上在JVM会将这些常量表存储在方法区中一块连续的内存空间中,因此class文件会根据常量表在常量池中的位置对其进行索引。比如常量池中的第一个常量表的索引值就是1,第二个就是2。有的时候常量表A需要常量表B的内容,则在常量表A中会存储常量表B的索引值x。而constant_pool_count就记录了有多少个常量表,或则所有多少个索引值。实际上,常量池中没有索引值为0的常量表,但这缺失的索引值也被记录在 constant_pool_count中,因此 constant_pool_count等于常量表的数量加1。

常量池计数器(constant_pool_count):常量表(cp_info)数量+1。

常量表(cp_info):constant_pool_count-1个。

澳门美高梅游戏 3

常量表结构(cp_info)

每个常量表(cp_info) 都会对应记录着class文件中的某中类型的字面量

这14种表有一个共同的特点,就是开始的第一位是一个u1类型的标志位(tag,就是上表中的标志这一列),代表当前这个常量属于哪种常量类型。

 澳门美高梅游戏 4

澳门美高梅游戏 5

字符串常量池:

基本类型常量池:

**item4:访问标志(access_flags)[u2]**  

表明该class文件中定义的是类还是接口,访问修饰符是public还是缺省。类或接口是否是抽象的。类是否是final的。

澳门美高梅游戏 6

**item5:类索引(this_class) [u2]、父类索引(super_class)[u2]、接口索引集合(inteface_count、interfaces )[u2,u2]**

1、Class文件通过这三项数据来确定这个类的继承关系。

2、类索引用于确定这个类的全限定名。

3、父类索引用于确定这个类的父类的全限定名。由于Java语言不允许多重继承,所以父类索引只有一个。

4、除了java.lang.Object之外,所有的Java类都有父类,因此除了java.lang.Object外,所有Java类的父类索引都不为0。

5、接口索引集合就用来描述这个类实现了哪些接口。

6、类索引和父类索引用两个u2类型的索引值表示,它们各自指向一个类型为CONSTANT_Class_info的类描述符常量,通过CONSTANT_Class_info类型的常量中的索引值可以找到定义在CONSTANT_Utf8_info类型的常量中的全限定名字符串。

7、对于接口索引集合,入口的第一项:u2类型的数据为接口计数器(interfaces_count),表示索引表的容量。如果该类没有实现任何接口,则该计数器值为0,后面接口的索引表不再占用任何字节。

**item6:字段表集合(field_count,fields) [u2,field_info]**

1、字段表(field_info)用于描述接口或者类中声明的变量。

2、字段(field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。

field_info表格式

access_flags(2byte 访问修饰符)

name_index(2byte 存储字段名的常量表在常量池中的索引)

description_index(2byte 存储字段的所属类型的常量表在常量池中的索引)

attribute_count(2byte 属性表的数量)

attribute (属性)

其中attribute是由多个attribute_info组成。而JVM规范定义了字段的三种属性:ConstanceValue、Deprecated和Synthetic。

 

澳门美高梅游戏 7

 

 

**item7:方法表集合(method_count、methods) [u2,method_info]** 

method_count、methods 与字段类似,method_count表明类中方法的数量和每个方法的常量表的索引。methods表明了不同长度的method_info表的序列。

method_info表格式

access_flags(2byte 访问修饰符)

name_index(2byte 存储方法名的常量表在常量池中的索引)

description_index(2byte 存储方法的返回类型和参数类型的常量表在常量池中的索引)

attribute_count(2byte 属性表的数量)

attribute (属性)

其中方法的属性JVM规定了四种:Code,Deprecated,Exceptions,Synthetic。

 

简单名称:方法名如:fun,字段名如:str1

全限定名:com/mobjia/clazz/TestClass

描述符:

描述符的作用是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值。

根据描述符规则,基本数据类型(byte、char、double、float、int、long、short、boolean)以及代表无返回值的void类型都用一个大写字符来表示,而对象类型则用字符L加对象的全限定名来表示。

澳门美高梅游戏 8

数组类型:每一维度将使用一个前置的“[”字符来描述,如一个定义为“java.lang.String[][]”类型的二维数组,将被记录为:“[[Ljava/lang/String;”,一个整型数组“int[]”将被记录为“[I”。

用描述符来描述方法时,按照先参数列表,后返回值的顺序描述,参数列表按照参数的严格顺序放在一组小括号“()”之内。

void inc()的描述符为()V
java.lang.String toString()的描述符()Ljava/lang/String;
int indexOf(char[]source,int sourceOffset,int sourceCount,char[]target,int targetOffset,inttargetCount,int fromIndex)的描述符 ([CII[CIII)I

 

Class实例分析

工具:WinHe十六进制编辑器

 

参考:

 

当JVM运行Java程序的时候,它会加载对应的class文件,并提取class文件中的信息存放在JVM的方法区内存中。 Cl...

1.1.无符号数

2 纵观Class文件结构

class文件是一组以8位字节为基础单位的二进制流,它的内容具有严格的规范,文件中没有任何分隔符,全是连续的0/1.
class文件中的所有内容被分为两种类型:无符号数 和 表。

  • 无符号数
    基本的数据类型,以u1、u2、u4、u8,分别代表1字节、2字节、4字节、8字节的无符号数.

  • class文件中所有数据(即无符号数)要么单独存在,要么由多个无符号数组成二维表.即class文件中的数据要么是单个值,要么是二维表.

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

2.1 魔数(Magic Number)

class文件的头4个字节称为魔数,唯一作用是确定这个文件是否为一个能被JVM接受的Class文件.
作用就相当于文件后缀名,只不过后缀名容易被修改,不安全.
是用16进制表示的"CAFEBABE".

1.2.表

2.2 版本信息

紧接着魔数的4个字节是版本号.它表示本class中使用的是哪个版本的JDK.
在高版本的JVM上能够运行低版本的class文件,但在低版本的JVM上无法运行高版本的class文件.

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

2.3 常量池

澳门美高梅游戏 9

2.3.1 什么是常量池?

紧接着版本号之后的就是常量池.常量池中存放两种类型的常量:

  • 字面量 (Literal)
    接近Java语言的常量概念如:文本字符串、final常量值等.
  • 符号引用 (Symbolic Reference)
    属于编译原理方面,包括下面三类常量:
  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

2.1.魔数

2.3.2 常量池的特点

  • 常量池长度不固定
    常量池的大小是不固定的,因此常量池开头放置一个u2类型的无符号数,代表当前常量池的容量.
    注:这个值是从1开始,若为5表示池中有4项常量,索引值1~5.
  • 常量池中的常量由二维表来表示
    开头有个常量池容量计数值,接下来就全是一个个常量了,只不过常量都是由一张张二维表构成,除了记录常量的值以外,还记录当前常量的相关信息.
  • 常量池是class文件的资源仓库
  • 常量池是与本class中其它部分关联最多的数据类型
  • 常量池是占用Class文件空间最大的部分之一 ,也是第一个出现的表类型项目

class文件的头4个字节称为魔数,它的唯一作用是确定这个文件能否为一个能被虚拟机接受的Class文件。

2.3.3 常量池中常量的类型

刚才介绍了,常量池中的常量大体上分为:字面量 和 符号引用.在此基础上,根据常量的数据类型不同,又可以被细分为14种常量类型.这14种常量类型都有各自的二维表示结构.每种常量类型的头1个字节都是tag,表示当前常量属于14种类型中的哪一个.

这里写图片描述

以CONSTANT_Class_info常量为例,它的二维表示结构如下:
CONSTANT_Class_info表:
[图片上传失败...(image-847fbb-1513661176215)]
tag表示当前常量的类型(当前常量为CONSTANT_Class_info,因此tag的值应为7,表示一个类或接口的全限定名);
name_index表示这个类或接口全限定名的位置.它的值表示指向常量池的第几个常量.它会指向一个CONSTANT_Utf8_info类型的常量,它的二维表结构如下:
CONSTANT_Utf8_info表:
[图片上传失败...(image-c16889-1513661176215)]
CONSTANT_Utf8_info表示字符串常量;
tag表示当前常量的类型,这里应该是1;
length表示这个字符串的长度;
bytes为这个字符串的内容(采用缩略的UTF8编码)

澳门美高梅游戏 ,问:为什么Java中定义的类、变量名字必须小于64K?
类、接口、变量等名字都属于符号引用,它们都存储在常量池中。而不管哪种符号引用,它们的名字都由CONSTANT_Utf8_info类型的常量表示,这种类型的常量使用u2存储字符串的长度。由于2字节最多能表示65535个数,因此这些名字的最大长度最多只能是64K。

问:什么是UTF-8编码?什么是缩略UTF-8编码?
前者每个字符使用3个字节表示,而后者把128个ASKII码用1字节表示,某些字符用2字节表示,某些字符用3字节表示。

魔数的作用就相当于文件后缀名,只不过后缀名容易被修改,不安全,因此在class文件中标示文件类型比较合适。

2.4 访问标志

在常量池结束之后是2字节的访问标志.表示这个class文件是类还是接口、是否被public修饰、是否被abstract修饰、是否被final修饰等.
由于这些标志都由是/否表示,因此可以用0/1表示.
访问标志为2字节,可以表示16位标志,但JVM目前只定义了8种,未定义的直接写0.

这里写图片描述

class文件的魔数是用16进制表示的“CAFEBABE”,非常具有浪漫主义色彩,谁说程序员的情商都很低!

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

表示当前class文件所表示类的名字、父类名字、接口们的名字.
它们按照顺序依次排列,类索引和父类索引各自使用一个u2类型的无符号常量,这个常量指向CONSTANT_Class_info类型的常量,该常量的bytes字段记录了本类、父类的全限定名.
由于一个类的接口可能有好多个,因此需要用一个集合来表示接口索引,它在类索引和父类索引之后.这个集合头两个字节表示接口索引集合的长度,接下来就是接口的名字索引.

2.2.版本号

2.6 字段表的集合

紧接着魔数的四个字节是class文件的此版本号和主版本号。 随着Java的发展, class文件的格式也会做相应的变动。 版本号标志着class文件在什么时候, 加入或改变了哪些特性。 举例来说, 不同版本的javac编译器编译的class文件, 版本号可能不同, 而不同版本的JVM能识别的class文件的版本号也可能不同, 一般情况下, 高版本的JVM能识别低版本的javac编译器编译的class文件, 而低版本的JVM不能识别高版本的javac编译器编译的class文件。 如果使用低版本的JVM执行高版本的class文件,JVM会抛出java.lang.UnsupportedClassVersionError 。

2.6.1 什么是字段表集合?

用于存储本类所涉及到的成员变量,包括实例变量和类变量,但不包括方法中的局部变量.
每一个字段表只表示一个成员变量,本类中所有的成员变量构成了字段表集合.

2.3.常量池

2.6.2 字段表结构的定义

这里写图片描述

  • access_flags
    字段的访问标志。在Java中,每个成员变量都有一系列的修饰符,和上述class文件的访问标志的作用一样,只不过成员变量的访问标志与类的访问标志稍有区别。
  • name_index
    本字段名字的索引。指向一个CONSTANT_Class_info类型的常量,这里面存储了本字段的名字等信息。
  • descriptor_index
    描述符。用于描述本字段在Java中的数据类型等信息(下面详细介绍)
  • attributes_count
    属性表集合的长度。
  • attributes
    属性表集合。到descriptor_index为止是字段表的固定信息,光有上述信息可能无法完整地描述一个字段,因此用属性表集合来存放额外的信息,比如一个字段的值。(下面会详细介绍)

2.3.1. 什么是常量池?

2.6.3 什么是描述符?

成员变量(包括静态成员变量和实例变量) 和 方法都有各自的描述符。
对于字段而言,描述符用于描述字段的数据类型;
对于方法而言,描述符用于描述字段的数据类型、参数列表、返回值。

在描述符中,基本数据类型用大写字母表示,对象类型用“L对象类型的全限定名”表示,数组用“[数组类型的全限定名”表示。
描述方法时,将参数根据上述规则放在()中,()右侧按照上述方法放置返回值。而且,参数之间无需任何符号。

紧接着版本号之后的就是常量池。常量池中存放两种类型的常量:字面值常量和符号引用。

美高梅集团手机版 ,2.6.4 字段表集合的注意点

  • 一个class文件的字段表集合中不能出现从父类/接口继承而来字段;
  • 一个class文件的字段表集合中可能会出现程序猿没有定义的字段
    如编译器会自动地在内部类的class文件的字段表集合中添加外部类对象的成员变量,供内部类访问外部类。
  • Java中只要两个字段名字相同就无法通过编译。但在JVM规范中,允许两个字段的名字相同但描述符不同的情况,并且认为它们是两个不同的字段。

字面值常量即我们在程序中定义的字符串、被final修饰的值。

2.7 方法表的集合

在class文件中,所有的方法以二维表的形式存储,每张表来表示一个函数,一个类中的所有方法构成方法表的集合。
方法表的结构和字段表的结构一致,只不过访问标志和属性表集合的可选项有所不同。

这里写图片描述

方法表的属性表集合中有一张Code属性表,用于存储当前方法经编译器编译过后的字节码指令。

符号引用就是我们定义的各种名字:类和接口的全限定名、字段的名字 和 描述符、方法的名字 和 描述符。

方法表集合的注意点

  • 如果本class没有重写父类的方法,那么本class文件的方法表集合中是不会出现父类/父接口的方法表;
  • 本class的方法表集合可能出现程序猿没有定义的方法
    编译器在编译时会在class文件的方法表集合中加入类构造器和实例构造器。
  • 重载一个方法需要有相同的简单名称和不同的特征签名。JVM的特征签名和Java的特征签名有所不同:
  • Java特征签名:方法参数在常量池中的字段符号引用的集合
  • JVM特征签名:方法参数+返回值

2.3.2 常量池的特点

2.8 属性表的集合

常量池长度不固定

常量池的大小是不固定的,因此常量池开头放置一个u2类型的无符号数,用来存储当前常量池的容量。JVM根据这个值就知道常量池的头尾来。

注:这个值是从1开始的,若为5表示池中有4个常量。

常量池中的常量由而为表来表示

常量池开头有个常量池容量计数器,接下来就全是一个个常量了,只不过常量都是由一张张二维表构成,除了记录常量的值以外,还记录当前常量的相关信息。

常量池是class文件的资源仓库

常量池是与本class中其它部分关联最多的部分

常量池是class文件中空间占用最大的部分之一

2.3.3常量池中常量的特点

刚才介绍了,常量池中的常量大体上分为:字面值常量 和 符号引用。在此基础上,根据常量的数据类型不同,又可以被细分为14种常量类型。这14种常量类型都有各自的二维表示结构。每种常量类型的头1个字节都是tag,用于表示当前常量属于14种类型中的哪一个。

以CONSTANT_Class_info常量为例,它的二维表示结构如下:

CONSTANT_Class_info表:

类型名称数量

u1tag1

u2name_index1

tag表示当前常量的类型(当前常量为CONSTANT_Class_info,因此tag的值应为7,表示一个类或接口的全限定名);

name_index表示这个类或接口全限定名的位置。它的值表示指向常量池的第几个常量。它会指向一个CONSTANT_Utf8_info类型的常量,它的二维表结构如下:

CONSTANT_Utf8_info表:

编辑:美高梅集团 本文来源:无符号数属于基本的数据类型,分割成若干个8位

关键词: