平台无关性:是建立在操作系统上,虚拟机厂商提供了多种运行在各种不同平台的虚拟机,它们都可以载入和执行字节码,从而实现程序的“一次编写,到处运行”。
各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(ByteCode)是构成平台无关性的基石,也是语言无关性的基础。
语言无关性:Java 虚拟机不和包括 Java 在内的任何语言绑定,它只与“Class 文件”这种特定的二进制文件格式所关联,(其他语言也可以运行在jvm),Class 文件中包含了 Java 虚拟机指令集和符号表以及若干其他辅助信息。
所有Class文件都对应着唯一一个类或接口的定义信息,但反过来说,Class 文件实际上它并不一定以磁盘文件的形式存在(可内存)。Class 文件是一组以 8 位字节为基础单位的二进制流。
class文件没有任何分隔符号,在其中的数据项,无论是顺序还是数量,都是被严格限定的,哪个字节代表什么含义,长度是多少,先后顺序如何,都不允许改变.
按顺序包括:前四个字节称为魔数,它的唯一作用是确定这个文件是否为一个能被虚拟机接受的 Class 文件。使用魔数而不是扩展名来进行识别主要是基于安全方面的考虑,因为文件扩展名可以随意地改动。
紧接着魔数的四个字节存储class版本号,第5和第6个字节是次版本号(MinorVersion),第7和第8个字节是主版本号(Major Version)。
Java的版本号是从 45 开始的,34(十六进制)换算十进制为52即JDK1.8。
常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项 u2 类型的数据,代表常量池容量计数值(constant_pool_count)。与 Java 中语言习惯不一样的是,这个容量计数是从 1 而不是0开始的。
常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。
字面量比较接近于 Java 语言层面的常量概念,如文本字符串、声明为 final 的常量值等。
而符号引用则属于编译原理方面的概念,包括了下面三类常量:
类和接口的全限定名(Fully Qualified Name)、字段的名称和描述符(Descriptor)、方法的名称和描述符
用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口;是否定义为 public 类型;是否定义为 abstract 类型;如果是类的话,是否被声明为 final 等。
这三项数据来确定这个类的继承关系。
类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。由于 Java 语言不允许多重继承,所以父类索引只有一个,除了 java.lang.Object 之外,所有的 Java 类都有父类,因此除了 java.lang.Object 外,所有 Java 类的父类索引都不为 0。
接口索引集合就用来描述这个类实现了哪些接口,这些被实现的接口将按 implements 语句(如果这个类本身是一个接口,则应当是 extends 语句)后的接口顺序从左到右排列在接口索引集合中
描述接口或者类中声明的变量。字段(field)包括类级变量以及实例级变量。
描述了方法的定义,但是方法里的 Java 代码,经过编译器编译成字节码指令后,存放在属性表集合中的方法属性表集合中一个名为“Code”的属性里面。
与字段表集合相类似的,如果父类方法在子类中没有被重写(Override),方法表集合中就不会出现来自父类的方法信息。但同样的,有可能会出现由编译器自动添加的方法,最典型的便是类构造器“<clinit>”方法和实例构造器“<init>”
存储 Class 文件、字段表、方法表都自己的属性表集合,以用于描述某些场景专有的信息。如方法的代码就存储在 Code 属性表中。