语言无关性

语言无关系的关键在 于 JVM字节码;Java虚拟机不与任何编译成class字节码的语言绑定,只要能够编译成有效的Class字节码都解析执行。


一、Class文件结构

任何一个Class文件都对应着唯一 一个类或接口的定义信息,但反过来说,类或接口并不一定都得定义在文件里(譬如类或接口也可以通过类加载器直接生成)。


问题: 当出现超过8位字节码来表示的数据项怎么办呢?

会按照高位在前的方式分割成若干个8位字节进行存储;补充大端法小端法


二 如何描述Class文件

无符号 组合成类似与C结构的伪结构来描述Class文件。


三、ClassFile Structure

一个class 由单个ClassFile 结构组成。ClassFile由下面结构组成。

ClassFile {u4             magic;        //识别Class文件格式,具体值为0xCAFEBABE; 即魔术u2             minor_version;//次版本号u2             major_version;//主版本号u2             constant_pool_count;//常量池容量计数cp_info        constant_pool[constant_pool_count-1];//它代表各种各样的字符串常量、类和接口名、字段名以及在ClassFile结构及其子结构中引用的其他常量。//每个常量池表条目的格式由它的第一个“标记”字节表示。u2             access_flags;     //访问标志u2             this_class;       //类索引u2             super_class;     //父类索引u2             interfaces_count;//接口索引数u2             interfaces[interfaces_count]; //接口索引集合//接口数组中的每个值必须是常量池中有效索引。u2             fields_count;     //字段数    field_info     fields[fields_count];u2             methods_count;   //方法数method_info    methods[methods_count]; u2             attributes_count;  //属性数attribute_info attributes[attributes_count];
}

3.1 文件结构解析

Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符


特定描述
8位字节为单位
顺序有严格控制
大小有规律,因为表是符合结构数据,大小不确定外,其他都是大小确定的。

类型

描述Class类文件结构的类型

类型 描述
无符号 u1u2u4u8来分别代表1个字节2个字节4个字节8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值。
表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以_info结尾。表用于描述有层次关系的复合结构的数据

3.2 字节码文件解析

将下面一点代码使用JDK1.8编译成Class文件进行讲解


package org.fenixsoft.clazz;public class TestClass {private int m;public int inc() {return m + 1;}
}

通过命令javac将这个类编译成classs文件。notepad++装一个HEX-Editor 插件后,打开这个class文件。


接下来就是解析这份字节码。


3.2.1 魔术 cafe babe

  u4             magic; 

每个Class文件的头四个字节称为魔数,它的唯一作用是用来确定该文件是否为一个能被虚拟机接受的Class文件。使用魔数而不使用文件扩展名是出于安全方面的考虑,因为文件扩展名可以很随意的被改动。


3.2.2 版本号

 u2             minor_version;//次版本号u2             major_version;//主版本号

minor_version:占2字节,次版本号,0x0000
majro_version:占2字节,主版本号,0x0034, 转换过来就是52


3.2.3 常量池(constant_pool_count 和 constant_pool)

ClassFile {
...u2             constant_pool_count;cp_info        constant_pool[constant_pool_count-1];
...
}

constant_pool_count : 由于常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值 (计数从1开始,其他计数从0开始,因为0有其他作用)


(一) 常量池数目:

常量池容量(偏移地址:0x00000008)为十六进制数0x0016,即十进制的22,这就代表常量池中有21项常量,索引值范围为1~21


(二)常量池内容:

constant_pool : 主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。

在Class文件中不会保存各个方法、字段的最终内存布局信息,因此这些字段、方法的符号引用不经过运行期转换的话无法得到真正的内存入口地址,也就无法直接被虚拟机使用。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析翻译到具体的内存地址之中

常量池的都是表结构,如上图展示,但是在常量池中的表的结构又是怎么样的呢?


注意:所有常量池中的条码都具有下面通用结构:

cp_info {u1 tag;u1 info[];
}

每个条码都有一个tag 去标志它


结合Class字节码来讲解常量池中各个类型的结构

下面圈定了常量池中的内容,通过tag 定位到具体哪个类型,根据类型的结构进行逐一分析


按照常量池中类型,整理出21个记录

序号 字节码 常量池类型 字符串
1 0a 00 04 00 12 CONSTANT_Methodref_info
2 09 00 03 00 13 CONSTANT_Fieldref
3 07 00 14 CONSTANT_Class
4 07 00 15 CONSTANT_Class
5 01 00 01 6d CONSTANT_Utf8_info m
6 01 00 01 49 CONSTANT_Utf8_info i
7 01 00 06 36 69 6e 69 74 3e CONSTANT_Utf8_info
8 01 00 03 28 29 56 CONSTANT_Utf8_info ()
9 01 00 04 43 6f 64 65 CONSTANT_Utf8_info Code
10 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 65 CONSTANT_Utf8_info LineNumberTable
11 01 00 12 4c 6f 63 61 6c 56 72 69 61 62 6c 65 54 61 62 6c 65 CONSTANT_Utf8_info LocalVariableTable
12 01 00 04 74 68 69 73 CONSTANT_Utf8_info this
13 01 00 1f 4c 6f 72 67 2f 66 65 6e 69 78 73 6f 66 74 2f 63 6c 61 7a 7a 2f 54 65 73 74 43 6c 61 73 74 3b CONSTANT_Utf8_info Long/fenixsoft/clazz/TestClass;
14 01 00 03 69 6e CONSTANT_Utf8_info inc
15 01 00 03 28 29 49 CONSTANT_Utf8_info ()I
16 01 00 0a 53 6f 75 72 63 65 46 69 6c 65 CONSTANT_Utf8_info SourceFile
17 01 00 0e 54 65 73 74 43 6c 61 73 73 2e 6a 61 76 61 CONSTANT_Utf8_info TestClass.java
18 0c 00 07 00 08 CONSTANT_NameAndType
19 0c 00 05 00 06 CONSTANT_NameAndType
20 01 00 1d 6f 72 67 2f 66 65 6e 69 78 73 6f 66 74 2e 63 6c 61 7a 7a 2f 54 65 73 74 43 6c 61 73 73 CONSTANT_Utf8_info org/fenixsoft/clazz/TestClass
21 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 CONSTANT_Utf8_info java/lang/Object

constant_pool table 把上图看做常量池表; 可以理解为将所有


同时也可利用javap 命令整理



3.2.3.1 常量池分析

(一) 根据tag值找类型:

在常量池后面的第一个地址(偏移地址:0x0000000A),是 0x0A (十进制为10),tag=10; 找到Constant Pool tag 定位到了 CONSTANT_Methodref 这个类型。

(二) 结构类型:

Fields, methods, and interface methods 具有相似的结构

CONSTANT_Fieldref_info {u1 tag;u2 class_index;u2 name_and_type_index;
}CONSTANT_Methodref_info {u1 tag;u2 class_index;u2 name_and_type_index;
}CONSTANT_InterfaceMethodref_info {u1 tag;u2 class_index;u2 name_and_type_index;
}

分别对 CONSTANT_Methodref_infotag, class_index,name_and_type_index 进行介绍

items 描述
tag CONSTANT_Methodref_info结构的tag值为10
class_index CONSTANT_Methodref_info 结构的class_index必须是一个类类型,而不是接口类型
name_and_type_index name_and_type_index 的值必须是constant_pool表 中的一个有效索引;这索引值上的对应的常量池条目(The constant_pool entry) 也一定是CONSTANT_NameAndType_info 结构;这个条目也是具有字段或方法作为成员的类或接口类型

【entry 条目;词条;账目;记录 】

补充:假如CONSTANT_Methodref_info 结构的方法名称以'<' ('\u003c') 开始,那么这个方法一定是特定的 <init>; 代表一个实例初始方法,返回类型也一定是 void。


CONSTANT_NameAndType_info 结构类型

CONSTANT_NameAndType_info {u1 tag;u2 name_index;u2 descriptor_index;
}
  • tag: CONSTANT_NameAndType_infotag 值一定是 12

  • name_index : 它的值一定是constant_pool table(常量池表) 有效索引值。那个索引对应的constant_pool entry(常量池条目),一定是CONSTANT_Utf8_info 结构; 代表特定的 方法 名; 也可以表示字段或方法的有效限定名

  • descriptor_index: 它的值是constant_pool table(常量池表)的一个有效索引,这个constant_pool entry 将是一个CONSTANT_Utf8_info 为结构; 代表字段或者方法的描述符。


结构: CONSTANT_Utf8_info

CONSTANT_Utf8_info {u1 tag;u2 length;u1 bytes[length];
}

这个CONSTANT_Utf8_info 结构别用来表示常量字符串值。

  • tag:CONSTANT_Utf8_info 的tag值一定是 1
  • length: bytes数组的长度值;不是实际字符串的长度值。
  • bytes:字节数组包含了字符串的每个字节
    • 如果没有字节可是值为0
    • 也可能是因为没有字节分布于 [(byte)0xf0 , (byte)0xff] (0-255)

length值说明了这个UTF-8编码的字符串长度是多少字节,它后面紧跟着的长度为length字节的连续数据是一个使用UTF-8缩略编码表示的字符串。UTF-8缩略编码与普通UTF-8编码的区别是:从'\u0001'到'\u007f'之间的字符(相当于1~127的ASCII码)的缩略编码使用一个字节表示,从'\u0080'到'\u07ff‘之间的所有字符的缩略编码用两个字节表示,从'\u0800'到'\uffff'之间的所有字符的缩略编码就按照普通UTF-8编码规则使用三个字节表示


常量池中14中常量项结构总表

可以通过查阅总表来获取各项信息


没有出现在代码中的其他常量

其中有一些常量似乎从来没有在代码中出现过,如“I”“V”“<init>”“LineNumberTable”
“LocalVariableTable”等,这些看起来在代码任何一处都没有出现过的常量是哪里来的呢

3.2.4 访问标记(access_flags)

这个标志用于识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等

TestClass是一个普通Java类,不是接口、枚举或者注解,被public关键字修饰但没有被声明为final和abstract,并且它使用了JDK 1.2之后的编译器进行编译,因此它的ACC_PUBLICACC_SUPER标志应当为,而ACC_FINALACC_INTERFACEACC_ABSTRACTACC_SYNTHETICACC_ANNOTATIONCC_ENUM这6个标志应当为,因此它的access_flags的值应为:0x0001|0x0020=0x0021


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

类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类的继承关系


  • 类索引用(this_class)于确定这个类的全限定名,
  • 父类索引(super_class)用于确定这个类的父类的全限定名。
  • 由于Java语言不允许多重继承,所以父类索引只有一个; 但是接口可以实现好几个,所以是个集合,
  • 除了java.lang.Object之外, 所有的Java类都有父类,因此除了java.lang.Object外,所有Java类的父类索引都不为0

结构描述:


item desc
this_class this_class 的值一定是常量池中的有效索引,这个索引对应的常量项是一个CONSTANT_Class_info ;这个表示由这个类文件定义的类或接口
super_class 可能是0 ,或者是常量池中有效索引,这个索引对应的常量项是一个CONSTANT_Class_info;代表这个类文件对应类的父类;直接超类和它的任何超类都不能在其类文件结构的access flags项中设置ACC_FINAL 标志;加入这个值为0,那个这个文件一定是Object类
interfaces_count 接口数量
interfaces[] 数组中的每个值都必须是常量池中的有效索引,每个索引对应的常量项都是CONSTANT_Class_info 这样的结构。 顺序从左到右

因为interfaces_count 数量为 0 ,所以后面的interfaces[] 就不占用地址。


3.2.6 字段表集合

结合案例,字段表的数量为 1个;让后对这个进行分析

每个字段的结构都如下:

field_info {u2             access_flags;u2             name_index;u2             descriptor_index;u2             attributes_count;attribute_info attributes[attributes_count];
}

一个类文件中没有两个字段可能具有相同的名称和描述。

(一) 访问标识符( access_flags )如下:

标志 描述
ACC_PUBLIC 0x0001 public 访问修饰符
ACC_PRIVATE 0x0002 private 访问修饰符
ACC_PROTECTED 0x0004 protected 访问修饰符
ACC_STATIC 0x0008 static
ACC_FINAL 0x0010 final
ACC_VOLATILE 0x0040 valatile
ACC_TRANSIENT 0x0080 transient
ACC_SYNTHETIC 0x1000 synthetic
ACC_ENUM 0x4000 enum
对访问标识符的解释
ACC_PUBLICACC_PRIVATEACC_PROTECTED三个标志最多只能选择其一
接口中的字段必须有ACC_PUBLICACC_STATICACC_FINAL标志
ACC_ENUM标志指示该字段用于保存枚举类型的元素
ACC_SYNTHETIC标志表明该字段是由编译器生成的,并没有出现在源代码中

(二) name_index:

对常量池的引用, 其值为常量池中的有效索引,代表着字段的简单名称。

(三) descriptor_index:

  • 描述符的作用是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值。
  • 根据描述符规则,基本数据类型(byte、char、double、float、int、long、short、boolean)以及代表无返回值的void类型都用一个大写V字符来表示,而对象类型则用字符L加对象的全限定名来表示


  • 对于数组类型,每一维度将使用一个前置的[字符来描述,如一个定义为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,  int targetCount, int fromIndex)

描述符为([CII[CIII)I


字段表集合中不会列出从超类或者父接口中继承而来的字段,但有可能列出原本Java代码之中不存在的字段,譬如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。

另外,在Java语言中字段是无法重载的,两个字段的数据类型、修饰符不管是否相同,都必须使用不一样的名称,但是对于字节码来讲,如果两个字段的描述符不一致,那字段重名就是合法的



3.2.7 方法集合

结合案例,本次方法的数量为2

Class文件存储格式中对方法的描述与对字段的描述几乎采用了完全一致的方式

method_info {u2             access_flags;u2             name_index;u2             descriptor_index;u2             attributes_count;attribute_info attributes[attributes_count];
}

通过方法表结构,集合本文案例


(一) access_flags:


与属性进行对比:

  • 因为volatile关键字和transient关键字不能修饰方法,所以方法表的访问标志中没有了ACC_VOLATILE标志和ACC_TRANSIENT标志。
  • 与之相对的,synchronizednativestrictfpabstract关键字可以修饰方法,所以方法表的访问标志中增加了ACC_SYNCHRONIZEDACC_NATIVECC_STRICTFPACC_ABSTRACT标志。

(二) name_index:

(三) 描述符索引:

描述符索引

通过分析得出了public void init()


方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性表集合中一个名为Code的属性里面,属性表作为Class文件格式中最具扩展性的一种数据项目


与字段表集合相对应的,如果父类方法在子类中没有被重写(Override),方法表集合中就不会出现来自父类的方法信息。但同样的,有可能会出现由编译器自动添加的方法,最典型的便是类构造器<clinit>方法和实例构造器<init>


3.2.8 属性表(attribute_info)集合

在Class文件、字段表、方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息;限制相对其他表相对宽松一些。

对于每个属性,它的名称需要从常量池中引用一个CONSTANT_Utf8_info类型的常量来表示,而属性值的结构则是完全自定义的,只需要通过一个u4的长度属性去说明属性值所占用的位数即可。下面每个属性都具备的结构特征。

attribute_info {u2 attribute_name_index;u4 attribute_length;u1 info[attribute_length];
}

在分析方法表的时候已经讲述了一个Code属性
(一)Code属性描述

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

下面的图中就是Code.


Code的两个属性值:


类型 名称 数量 描述
u2 attribute_name_index 1 attribute_name_index是一项指向CONSTANT_Utf8_info型常量的索引,常量值固定为Code,它代表了该属性的属性名称
u4 attribute_length 1 attribute_length指示了属性值的长度
u2 max_stack 1 max_stack代表了操作数栈(Operand Stacks)深度的最大值。虚拟机运行的时候需要根据这个值来分配栈帧(StackFrame)中的操作栈深度
u2 max_locals 1 max_locals代表了局部变量表所需的存储空间
u4 code_length 1 code_length代表字节码长度;理论上一个方法的字节码不超过u4,但实际是u2,如果超过这个限制,javac会拒绝
u1 code code_length code是用于存储字节码指令的一系列字节流
u2 exception_table_length 1 异常表长度
exception_info exception_table exception_table_length
u2 attributes_count 1 属性数量
attribute_info attributes attributes_count

Code属性表中的code(字节码)

2a b7 00 0a b1
  • 读入2a,查表得0x2A对应的指令为aload_0,这个指令的含义是将第0个Slot中为reference类型的本地变量推送到操作数栈顶。
  • 读入b7,查表得0xB7对应的指令为invokespecial,这条指令的作用是以栈顶的reference类型的数据所指向的对象作为方法接收者,调用此对象的实例构造器方法、private方法或者它的父类的方法。这个方法有一个u2类型的参数说明具体调用哪一个方法,它指向常量池中的一个CONSTANT_Methodref_info类型常量,即此方法的方法符号引用。
  • 读入00 01,这是invokespecial的参数,查常量池得0x0001对应的常量为实例构造器<init>方法的符号引用。
  • 读入b1,查表得0xB1对应的指令为return,含义是返回此方法,并且返回值为void。这条指令执行后,当前方法结束。

Java虚拟机执行字节码是基于栈的体系结构。但是与一般基于堆栈的零字节指令又不太一样,某些指令(如invokespecial)后面还会带有参数


继续分析Code中的剩余两个属性:LineNumberTableLocalVariableTable

LineNumberTable属性用于描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系。它并不是运行时必需的属性,但默认会生成到Class文件之中,可以在Javac中分别使用-g:none-g:lines选项来取消或要求生成这项信息。

如果选择不生成LineNumberTable属性,对程序运行产生的最主要的影响就是当抛出异常时,堆栈中将不会显示出错的行号,并且在调试程序的时候,也无法按照源码行来设置断点

line_number_table是一个数量为line_number_table_length、类型为line_number_info的集合,line_number_info表包括了start_pcline_number两个u2类型的数据项,前者是字节码行号,后者是Java源码行号

归纳为下面的结构

LineNumberTable_attribute {u2 attribute_name_index;u4 attribute_length;u2 line_number_table_length;{   u2 start_pc;u2 line_number; } line_number_table[line_number_table_length];
}

.LocalVariableTable属性结构如下

LocalVariableTable_attribute {u2 attribute_name_index;u4 attribute_length;u2 local_variable_table_length;{   u2 start_pc;u2 length;u2 name_index;u2 descriptor_index;u2 index;} local_variable_table[local_variable_table_length];
}
  • LocalVariableTable属性用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,
  • 它也不是运行时必需的属性,但默认会生成到Class文件之中,
  • 可以在Javac中分别使用-g:none或-g:vars选项来取消或要求生成这项信息。

local_variable_info项

item desc
start_pclength 代表了这个局部变量的生命周期开始的字节码偏移量及其作用范围覆盖的长度,两者结合起来就是这个局部变量在字节码之中的作用域范围
name_indexdescriptor_index 指向常量池中CONSTANT_Utf8_info型常量的索引,分别代表了局部变量的名称以及这个局部变量的描述符
index 这个局部变量在栈帧局部变量表中Slot的位置。当这个变量数据类型是64位类型时(double和long),它占用的Slot为indexindex+1两个


另外一个方法(不做详细介绍了):


使用javap打印信息

args_size 为什么等于 一

<init>()和inc(),都没有参数的,为什么args_size会为1?
而且无论是在参数列表里还是方法体内,都没有定义任何局部变量,那Locals又为什么会等于1?

在任何实例方法里面,都可以通过this关键字访问到此方法所属的对象。这个访问机制对Java程序的编写很重要,而它的实现却非常简单,仅仅是通过Javac编译器编译的时候把对this关键字的访问转变为对一个普通方法参数的访问,然后在虚拟机调用实例方法时自动传入此参数而已。因此在实例方法的局部变量表中至少会存在一个指向当前对象实例的局部变量,局部变量表中也会预留出第一个Slot位来存放对象实例的引用,方法参数值从1开始计算。这个处理只对实例方法有效,如果inc()声明为static,那Args_size就不会等于1而是等于0


ClassFile 最后一个属性:


到这个地方整个class文件就大致讲完了


后记

  • 还有很多属性没有讲解;当分析到对应的表时查询官方文档即可
  • code 字节码指令还没有详细讲解;将在新的一篇中详细讲解。

参考

  • 《深入理解Java虚拟机》–周志明
  • 什么是大端法和小端法
  • 《深入理解java虚拟机》笔记——简析java类文件结构
  • JVM笔记5:Class文件结构
  • Java class文件格式之属性详解_动力节点java学院整理

解读Class类文件结构相关推荐

  1. java主类与源代码名称_Java高级编程基础:类文件结构解析,看穿Class代码背后的秘密...

    类文件结构 在说完了JVM内部结构后,接下来我们需要说一下另外一个非常重要的基础概念Class类结构. 我们既然知道了开发的Java源代码会首先被编译成字节码文件保存,JVM的类加载器会读取这些文件内 ...

  2. JVM学习笔记(Ⅰ):Class类文件结构解析(带你读懂Java字节码,这一篇就够了)

    JVM学习笔记(Ⅰ):Class类文件结构解析,带你读懂Java字节码 前言:本文属于博主个人的学习笔记,博主也是小白.如果有不对的地方希望各位帮忙指出.本文主要还是我的学习总结,因为网上的一些知识分 ...

  3. 《深入理解Java虚拟机》——类文件结构之魔数常量池

    相对于Java虚拟机的其他部分,这部分的内容我们只需要搞清楚下面两个方面的内容: 1.无关性 2.Class文件的结构与组成 我们都知道Java有个特性是:一次编写,到处运行.这里体现的是平台无关性, ...

  4. Class类文件结构、类加载机制以及字节码执行

    一.Class类文件结构 Class类文件严格按照顺序紧凑的排列,由无符号数和表构成,表是由多个无符号数或其他数据项构成的符合数据结构. Class类文件格式按如下顺序排列: 类型 名称 数量 u4 ...

  5. 深入理解JVM虚拟机(四):Class类文件结构(一)

    我们都知道Java中的class文件是经过Java编译器对Java类文件进行编译后的产物.我想有不在少数的C程序员在学习Java之后在认知上会粗略的认为C程序在经过编译后产生的.out文件与.clas ...

  6. 深入理解Java虚拟机知乎_深入理解Java虚拟机(类文件结构)

    深入理解Java虚拟机(类文件结构) 欢迎关注微信公众号:BaronTalk,获取更多精彩好文! 之前在阅读 ASM 文档时,对于已编译类的结构.方法描述符.访问标志.ACC_PUBLIC.ACC_P ...

  7. java class类文件结构

    平台无关性     Java是与平台无关的语言,这得益于Java源代码编译后生成的存储字节码的文件,即Class文件,以及Java虚拟机的实现.不仅使用Java编译器可以把Java代码编译成存储字节码 ...

  8. Java虚拟机:class类文件结构

    一.平台无关性: Java的无关性的实现,是由Java源代码编译后生成的字节码class文件和Java虚拟机实现的.无关性包括:平台无关性以及语言无关性. (1)平台无关性,是指java代码可以运行在 ...

  9. Class 类文件结构

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17675609 平台无关性 Java是与平台无关的语言,这得益于Java源代码编译后生成的存 ...

最新文章

  1. 汉字转换成html,汉字与16进制、汉字与Html转义符的转换
  2. java开心消消乐代码_今晚请屏住呼吸,开心消消乐拍电影了!
  3. Network| ICMP
  4. Qt designer设计界面
  5. Caffe学习记录:Cifar-10 自定义网络训练记录
  6. 计算机软硬件作品构思报告,计算机方面的实训报告
  7. hdu 5188 dfs+二分
  8. python之正则(一)
  9. 用唯一的颜色id编号实现OpenGL选择功能(OpenGL Selection Using Unique Color IDs )
  10. IDE工具的[多行光标编辑模式]
  11. WEB项目优化:雅虎优化网站的34条法则(转)
  12. 线性表的链式存储结构(C语言实现)
  13. STM32的函数ssert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  14. java联网游戏_Java实现简易版联网坦克对战小游戏(附源码)
  15. 数据缺失机制以及缺失值处理方式
  16. 2021ccpc网络预选赛部分题解
  17. Java 方法与C语言函数微区别
  18. 无法启动此程序,因为计算机丢失api-ms-win-crt-process-l1-1-0.dll
  19. 在线图书销售系统顺序图_良心好用的在线学习工具,你知道和不知道的,这里都有~...
  20. 一个好的web前端开发者,是怎么学习的?前端开发培训机构哪个比较好

热门文章

  1. 【接口篇 / DMZ】(5.2) ❀ 02. 固定 IP 宽带映射服务器到公网 ❀ FortiGate 防火墙
  2. 弹性IP(弹性公网IP)和固定IP的区别
  3. Android设计模式与应用场景
  4. qduoj 80 树结构重逢(树形DP)
  5. web无序列表去掉点_HTML 无序列表项目符号使用图片的CSS写法
  6. STlink、Jlink驱动一直安装失败的解决办法
  7. 找出元音字母a,e,i,o,u出现的次数
  8. C++——函数声明省略形参名的用法注意
  9. 表格html适应手机端,纯CSS实现响应式表格适应移动端
  10. 10.29关于数字大爆炸游戏规则的重新理解以及重打