- 浏览: 269472 次
- 性别:
- 来自: 石家庄
最新评论
-
路小尘:
mark
详解 Java 语言中 float 类型的运算 -
ezerg:
兄弟,你那样写的效果和没写是一样的,因为你没有转换编码。例如从 ...
JDBC 中 DatabaseMetaData 接口的使用 -
yl419440513:
我也用的是这个,可是却被一个问题难住了,就是getString ...
JDBC 中 DatabaseMetaData 接口的使用 -
laijinyan:
我初学请教下不是说 MaxClients 要小于 Server ...
Apache 的 httpd 进程占用大量内存原因及其解决方案 -
ybb896:
,不错
安装和使用 percona 推出的 Xtrabackup 备份 MySQL
了解 .class 的文件结构,有助于加深对 Java 语言的理解和程序的优化。特别是深入了解之后,可以从原理上理解 Java 语言的很多底层的技术。
针对上一次利用 ASM 修改字节码的内容,以下的内容可能更难理解一些,也需要一些虚拟机字节码方面的知识。
Java 编译后的 .class 文件主要分为以下五个部分(个人理解):
1、魔数和版本号信息
2、常量池信息,包括池中常量的数量和每个常量的描述
3、类信息,包括本身类、父类和接口描述
4、类中声明的属性和方法信息,包括属性和方法的数量和描述,方法中还包括实际执行的虚拟机字节码
5、类本身属性的信息,例如 SourceFile 属性显示类的源文件名称
以下面的 Java 源文件为例,按照上面五个部分说明一下编译后的 .class 文件的格式。
注意:以下使用的数字如无特别说明均为 十六进制。
第一部分占用 8 个字节:
前面 4 个字节是魔数,所有 .class 文件都是一样的,为了虚拟机更方便的识别是否为类文件
后面 4 个字节分别是主版本号和次版本号,每个版本 JDK 的编译出的类会有所不同
第二部分占用的字节数取决的常量池的数量和常量的类型:
前面两个字节 0029 表示常量池的大小 40 个,常量池的内容会被后面所有部分使用到。
第1个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=0002,查看 2 个常量
第2个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0010 说明占用后面的 16 个字节。内容为 test/PrintString
第3个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=0004,查看 4 号常量
第4个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0010 说明占用后面的 16 个字节。内容为 java/lang/Object
第5个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0003 说明占用后面的 3 个字节。内容为 str
第6个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0012 说明占用后面的 18 个字节。内容为 Ljava/lang/String;
第7个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0006 说明占用后面的 6 个字节。内容为 <init>
第8个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0003 说明占用后面的 4 个字节。内容为 ()V
第9个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0004 说明占用后面的 4 个字节。内容为 Code
第10个常量 0A 是一个 constant_methodref 类型,后面的 4 个字节属于它,class_index=0003,name_and_type_index=000B。内容为 java/lang/Object 的 init 方法
第11个常量 0C 是一个 constant_nameAndType 类型,后面的 4 个字节属于它,name_index=0007,descriptor_index=0008,内容为<init>()V
第12个常量 08 是一个 constant_String 类型,后面的 2 个字节属于它,000D 查看13号常量池
第13个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 00 说明占用后面的 0 个字节。内容为空
第14个常量 09 是一个 constant_Fieldref 类型,后面的 4 个字节表示它占用的字节数,class_index=0001 , name_and_type_index =000F。内容为 test/PrintString 的 str
第15个常量 0C 是一个 constant_nameAndType 类型,后面的 4 个字节属于它,name_index=0005,descriptor_index=0006,。内容为 Ljava/lang/String; str
第16个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,000F 说明占用后面的 15 个字节。内容为 LineNumberTable
第17个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0012 说明占用后面的 18个字节。内容为 LocalVariableTable
第18个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0004 说明占用后面的 4个字节。内容为 this
第19个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0012 说明占用后面的 18个字节。内容为 Ltest/PrintString;
第20个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0009 说明占用后面的 9个字节。内容为 setString;)
第21个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0015 说明占用后面的 21个字节。内容为 (Ljava/lang/String;)V
第22个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0001 说明占用后面的 1个字节。内容为 s
第23个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0009 说明占用后面的 9个字节。内容为 getString
第24个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0014 说明占用后面的 20个字节。内容为 ()Ljava/lang/String;
第25个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0005 说明占用后面的 20个字节。内容为 print
第26个常量 09 是一个 constant_Fieldref 类型,根据它的定义后面四个字节属于它,class_index=001B 查看27号常量, name_and_type_index = 001D 查看29号常量
第27个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=001C,查看28号常量
第28个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0010 说明占用后面的 16个字节。内容为 java/lang/System
第29个常量 0C 是一个 constant_nameAndType 类型,根据它的定义后面的4个字节属于它,name_index=001E 查看30号常量,descriptor_index=001F 查看31号常量
第30个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 03 说明占用后面的 3个字节。内容为 out
第31个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 15 说明占用后面的 21个字节。内容为Ljava/io/PrintStream;
第32个常量 0A 是一个 constant_methodref 类型,后面的 4 个字节属于它,class_index=0001,name_and_type_index=0021
第33个常量 0C 是一个 constant_nameAndType 类型,根据它的定义后面的4个字节属于它,name_index=0017 查看23号常量,descriptor_index=0018 查看24号常量
第34个常量 0A 是一个 constant_methodref 类型,后面的 4 个字节属于它,class_index=0023 查看35号常量,name_and_type_index=0025 查看37号常量
第35个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=00 24,查看36号常量
第36个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 13 说明占用后面的 19个字节。内容为 java/io/PrintStream
第37个常量 0C 是一个 constant_nameAndType 类型,根据它的定义后面的4个字节属于它,name_index=0026 查看38号常量,descriptor_index=0015 查看21号常量
第38个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0007 说明占用后面的 7个字节。内容为 println
第39个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,000A 说明占用后面的 10个字节。内容为 SourceFile
第40个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 10 说明占用后面的 16个字节。内容为 PrintString.java
第三部分占用 8 个字节:
前面 2 个字节 0021 表示类本身的修饰符
中间 2 个字节 0001 表示类本身的常量表索引,内容为 test/PrintString
下面 2 个字节 0003 表示父类的常量表索引,内容为 java/lang/Object
最后 2 个字节 0000 表示类实现的接口数量,此类未实现接口
第四部分是类文件是比较复杂的部分,它分为两个部分:属性区和方法区。
先看属性区:
前面 2 个字节 0001 表示类声明了一个属性
下面 2 个字节 0002 表示后面 2 个字节是属性的描述
下面 2 个字节 0005 表示属性名称的常量池索引,5号常量的信息 str
下面 2 个字节 0006 表示属性描述的常量池索引,6号常量的信息 Ljava/lang/String;
最后 2 个字节 0000 表示属性本身的属性的数量
再看方法区:
前面 2 个字节 0004 表示类声明四个方法(注意:包含一个隐含的构造方法 init)
下面 2 个字节 0001 表示是一个ACC_PUBLIC 的方法
下面 2 个字节 0007 表示 name_index,表示常量池中第7个常量为<init>,
下面 2 个字节 0008 表示desciptor_index,表示常量池第8个常量为 ()V
下面 2 个字节 0001 表示attribute_count,表示有1个attribute
下面 2 个字节 0009 表示code_attribute,查看第9号常量池为Code
下面4 个字节 0000003D 表示后面的 61 个字节属于这个属性
下面 2 个字节 0002 表示 max_stack 该方法执行的时候操作数栈最大的长度,这里表示操作数栈的长度为1
下面 2 个字节 0001 表示 max_locals 该方法局部变量所需要的空间的长度
下面 4 个字节 00 00 00 0B 表示code_length 即后面的 11 个字节为虚拟机字节码内容
代码的 11 个字节:2A B7 00 0A 2A 12 0C B5 00 0E B1
2A :aload_0 表示将第一个引用类型本地变量推送至栈顶
B7 :invokespecial 调用超类方法,后面的 000A,查看10号常量池 表示调用超类的init方法
2A :aload_0 表示将第一个引用类型本地变量推送至栈顶
12 :ldc 表示将一个常量池压入操作栈,后面的 0C 便是这个操作数,查看第13号常量池,为空
B5 :putfield 将操作栈的值赋给类变量,后面2个字节 000E 代表类变量的常量池索引,为 Ljava/lang/String; str
B1 : return ;返回void
这里我们可以知道类变量的初始化位置。
代码的 11 个字节以后
下面 2 个字节 0000 表示exception_table_length=0;也就是说没有异常处理
下面 2 个字节 0002 表示attributes_count=2,接下来有两个attribute_info 的结构
下面 2 个字节 0010 表示 attribute_name_index,查看10号常量池,为 LineNumberTable
下面 4 个字节 00 00 00 0E 表示attribute_length=14
下面 14 个字节是 LineNumberTable 的属性
下面 2 个字节 0011 表示 attribute_name_index,查看10号常量池,为 LocalVariableTable
下面 4 个字节 00 00 00 0C 表示attribute_length=12
下面 12 个字节是 LocalVariableTable 的属性
以上只是第一个方法的说明,后面的方法不再详细说明。
第五部分通常不是很重要,大概了解一下:
前面 2 个字节 0001 表示接下去有一个 attributes_info 结构,该结构占用 8 个字节
下面 2 个字节 0027 表示属性的名称的常量池索引,39 号常量的信息(属性的名称)为 SourceFile
下面 4 个字节 00000002 表示属性的长度,因为格式固定,所长度为 2
最后 2 个字节 0028 表示 sourcefile_index 的常量池索引, 40 号常量的信息(源文件的名称)为 PrintString.java
以上只是对一个结构简单的类作了一个简要说明,实际情况会复杂很多。详细内容大家可以参考《深入 Java 虚拟机(第二版)》
针对上一次利用 ASM 修改字节码的内容,以下的内容可能更难理解一些,也需要一些虚拟机字节码方面的知识。
Java 编译后的 .class 文件主要分为以下五个部分(个人理解):
1、魔数和版本号信息
2、常量池信息,包括池中常量的数量和每个常量的描述
3、类信息,包括本身类、父类和接口描述
4、类中声明的属性和方法信息,包括属性和方法的数量和描述,方法中还包括实际执行的虚拟机字节码
5、类本身属性的信息,例如 SourceFile 属性显示类的源文件名称
以下面的 Java 源文件为例,按照上面五个部分说明一下编译后的 .class 文件的格式。
public class PrintString { private String str = ""; public void setString(String s) { this.str = s; } public String getString() { return this.str; } public void print(){ System.out.println(getString()); } }
注意:以下使用的数字如无特别说明均为 十六进制。
第一部分占用 8 个字节:
00000000h: CA FE BA BE 00 00 00 32 ; 漱壕...2
前面 4 个字节是魔数,所有 .class 文件都是一样的,为了虚拟机更方便的识别是否为类文件
后面 4 个字节分别是主版本号和次版本号,每个版本 JDK 的编译出的类会有所不同
第二部分占用的字节数取决的常量池的数量和常量的类型:
00000008h: 00 29 07 00 02 01 00 10 74 65 73 74 2F 50 72 69 ; .)......test/Pri 00000018h: 6E 74 53 74 72 69 6E 67 07 00 04 01 00 10 6A 61 ; ntString......ja 00000028h: 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 ; va/lang/Object.. 00000038h: 03 73 74 72 01 00 12 4C 6A 61 76 61 2F 6C 61 6E ; .str...Ljava/lan 00000048h: 67 2F 53 74 72 69 6E 67 3B 01 00 06 3C 69 6E 69 ; g/String;...<ini 00000058h: 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 0A ; t>...()V...Code. 00000068h: 00 03 00 0B 0C 00 07 00 08 08 00 0D 01 00 00 09 ; ................ 00000078h: 00 01 00 0F 0C 00 05 00 06 01 00 0F 4C 69 6E 65 ; ............Line 00000088h: 4E 75 6D 62 65 72 54 61 62 6C 65 01 00 12 4C 6F ; NumberTable...Lo 00000098h: 63 61 6C 56 61 72 69 61 62 6C 65 54 61 62 6C 65 ; calVariableTable 000000a8h: 01 00 04 74 68 69 73 01 00 12 4C 74 65 73 74 2F ; ...this...Ltest/ 000000b8h: 50 72 69 6E 74 53 74 72 69 6E 67 3B 01 00 09 73 ; PrintString;...s 000000c8h: 65 74 53 74 72 69 6E 67 01 00 15 28 4C 6A 61 76 ; etString...(Ljav 000000d8h: 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 ; a/lang/String;)V 000000e8h: 01 00 01 73 01 00 09 67 65 74 53 74 72 69 6E 67 ; ...s...getString 000000f8h: 01 00 14 28 29 4C 6A 61 76 61 2F 6C 61 6E 67 2F ; ...()Ljava/lang/ 00000108h: 53 74 72 69 6E 67 3B 01 00 05 70 72 69 6E 74 09 ; String;...print. 00000118h: 00 1B 00 1D 07 00 1C 01 00 10 6A 61 76 61 2F 6C ; ..........java/l 00000128h: 61 6E 67 2F 53 79 73 74 65 6D 0C 00 1E 00 1F 01 ; ang/System...... 00000138h: 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F ; ..out...Ljava/io 00000148h: 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 0A 00 01 ; /PrintStream;... 00000158h: 00 21 0C 00 17 00 18 0A 00 23 00 25 07 00 24 01 ; .!.......#.%..$. 00000168h: 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 ; ..java/io/PrintS 00000178h: 74 72 65 61 6D 0C 00 26 00 15 01 00 07 70 72 69 ; tream..&.....pri 00000188h: 6E 74 6C 6E 01 00 0A 53 6F 75 72 63 65 46 69 6C ; ntln...SourceFil 00000198h: 65 01 00 10 50 72 69 6E 74 53 74 72 69 6E 67 2E ; e...PrintString. 000001a8h: 6A 61 76 61 ; java
前面两个字节 0029 表示常量池的大小 40 个,常量池的内容会被后面所有部分使用到。
第1个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=0002,查看 2 个常量
第2个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0010 说明占用后面的 16 个字节。内容为 test/PrintString
第3个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=0004,查看 4 号常量
第4个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0010 说明占用后面的 16 个字节。内容为 java/lang/Object
第5个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0003 说明占用后面的 3 个字节。内容为 str
第6个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0012 说明占用后面的 18 个字节。内容为 Ljava/lang/String;
第7个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0006 说明占用后面的 6 个字节。内容为 <init>
第8个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0003 说明占用后面的 4 个字节。内容为 ()V
第9个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0004 说明占用后面的 4 个字节。内容为 Code
第10个常量 0A 是一个 constant_methodref 类型,后面的 4 个字节属于它,class_index=0003,name_and_type_index=000B。内容为 java/lang/Object 的 init 方法
第11个常量 0C 是一个 constant_nameAndType 类型,后面的 4 个字节属于它,name_index=0007,descriptor_index=0008,内容为<init>()V
第12个常量 08 是一个 constant_String 类型,后面的 2 个字节属于它,000D 查看13号常量池
第13个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 00 说明占用后面的 0 个字节。内容为空
第14个常量 09 是一个 constant_Fieldref 类型,后面的 4 个字节表示它占用的字节数,class_index=0001 , name_and_type_index =000F。内容为 test/PrintString 的 str
第15个常量 0C 是一个 constant_nameAndType 类型,后面的 4 个字节属于它,name_index=0005,descriptor_index=0006,。内容为 Ljava/lang/String; str
第16个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,000F 说明占用后面的 15 个字节。内容为 LineNumberTable
第17个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0012 说明占用后面的 18个字节。内容为 LocalVariableTable
第18个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0004 说明占用后面的 4个字节。内容为 this
第19个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0012 说明占用后面的 18个字节。内容为 Ltest/PrintString;
第20个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0009 说明占用后面的 9个字节。内容为 setString;)
第21个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0015 说明占用后面的 21个字节。内容为 (Ljava/lang/String;)V
第22个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0001 说明占用后面的 1个字节。内容为 s
第23个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0009 说明占用后面的 9个字节。内容为 getString
第24个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0014 说明占用后面的 20个字节。内容为 ()Ljava/lang/String;
第25个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0005 说明占用后面的 20个字节。内容为 print
第26个常量 09 是一个 constant_Fieldref 类型,根据它的定义后面四个字节属于它,class_index=001B 查看27号常量, name_and_type_index = 001D 查看29号常量
第27个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=001C,查看28号常量
第28个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0010 说明占用后面的 16个字节。内容为 java/lang/System
第29个常量 0C 是一个 constant_nameAndType 类型,根据它的定义后面的4个字节属于它,name_index=001E 查看30号常量,descriptor_index=001F 查看31号常量
第30个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 03 说明占用后面的 3个字节。内容为 out
第31个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 15 说明占用后面的 21个字节。内容为Ljava/io/PrintStream;
第32个常量 0A 是一个 constant_methodref 类型,后面的 4 个字节属于它,class_index=0001,name_and_type_index=0021
第33个常量 0C 是一个 constant_nameAndType 类型,根据它的定义后面的4个字节属于它,name_index=0017 查看23号常量,descriptor_index=0018 查看24号常量
第34个常量 0A 是一个 constant_methodref 类型,后面的 4 个字节属于它,class_index=0023 查看35号常量,name_and_type_index=0025 查看37号常量
第35个常量 07 是一个 constant_Class 类型,后面的 2 个字节属于它,name_index=00 24,查看36号常量
第36个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 13 说明占用后面的 19个字节。内容为 java/io/PrintStream
第37个常量 0C 是一个 constant_nameAndType 类型,根据它的定义后面的4个字节属于它,name_index=0026 查看38号常量,descriptor_index=0015 查看21号常量
第38个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,0007 说明占用后面的 7个字节。内容为 println
第39个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,000A 说明占用后面的 10个字节。内容为 SourceFile
第40个常量 01 是一个 constant_UTF8 类型,后面的 2 个字节表示它占用的字节数,00 10 说明占用后面的 16个字节。内容为 PrintString.java
第三部分占用 8 个字节:
000001ach: 00 21 00 01 00 03 00 00 ; .!......
前面 2 个字节 0021 表示类本身的修饰符
中间 2 个字节 0001 表示类本身的常量表索引,内容为 test/PrintString
下面 2 个字节 0003 表示父类的常量表索引,内容为 java/lang/Object
最后 2 个字节 0000 表示类实现的接口数量,此类未实现接口
第四部分是类文件是比较复杂的部分,它分为两个部分:属性区和方法区。
先看属性区:
000001b4h: 00 01 00 02 00 05 00 06 00 00 ; ..........
前面 2 个字节 0001 表示类声明了一个属性
下面 2 个字节 0002 表示后面 2 个字节是属性的描述
下面 2 个字节 0005 表示属性名称的常量池索引,5号常量的信息 str
下面 2 个字节 0006 表示属性描述的常量池索引,6号常量的信息 Ljava/lang/String;
最后 2 个字节 0000 表示属性本身的属性的数量
再看方法区:
000001beh: 00 04 00 01 00 07 00 08 00 01 00 09 00 00 00 3D ; ...............= 000001ceh: 00 02 00 01 00 00 00 0B 2A B7 00 0A 2A 12 0C B5 ; ........*?.*..? 000001deh: 00 0E B1 00 00 00 02 00 10 00 00 00 0E 00 03 00 ; ..?............ 000001eeh: 00 00 03 00 04 00 05 00 0A 00 03 00 11 00 00 00 ; ................ 000001feh: 0C 00 01 00 00 00 0B 00 12 00 13 00 00 // 此处为第一个方法和第二个方法的交界 00 01 00 ; ................ 0000020eh: 14 00 15 00 01 00 09 00 00 00 3E 00 02 00 02 00 ; ..........>..... 0000021eh: 00 00 06 2A 2B B5 00 0E B1 00 00 00 02 00 10 00 ; ...*+?.?...... 0000022eh: 00 00 0A 00 02 00 00 00 08 00 05 00 09 00 11 00 ; ................ 0000023eh: 00 00 16 00 02 00 00 00 06 00 12 00 13 00 00 00 ; ................ 0000024eh: 00 00 06 00 16 00 06 00 01 00 01 00 17 00 18 00 ; ................ 0000025eh: 01 00 09 00 00 00 2F 00 01 00 01 00 00 00 05 2A ; ....../........* 0000026eh: B4 00 0E B0 00 00 00 02 00 10 00 00 00 06 00 01 ; ?.?........... 0000027eh: 00 00 00 0C 00 11 00 00 00 0C 00 01 00 00 00 05 ; ................ 0000028eh: 00 12 00 13 00 00 00 01 00 19 00 08 00 01 00 09 ; ................ 0000029eh: 00 00 00 39 00 02 00 01 00 00 00 0B B2 00 1A 2A ; ...9........?.* 000002aeh: B6 00 20 B6 00 22 B1 00 00 00 02 00 10 00 00 00 ; ? ?"?........ 000002beh: 0A 00 02 00 00 00 10 00 0A 00 11 00 11 00 00 00 ; ................ 000002ceh: 0C 00 01 00 00 00 0B 00 12 00 13 00 00 ; .............
前面 2 个字节 0004 表示类声明四个方法(注意:包含一个隐含的构造方法 init)
下面 2 个字节 0001 表示是一个ACC_PUBLIC 的方法
下面 2 个字节 0007 表示 name_index,表示常量池中第7个常量为<init>,
下面 2 个字节 0008 表示desciptor_index,表示常量池第8个常量为 ()V
下面 2 个字节 0001 表示attribute_count,表示有1个attribute
下面 2 个字节 0009 表示code_attribute,查看第9号常量池为Code
下面4 个字节 0000003D 表示后面的 61 个字节属于这个属性
下面 2 个字节 0002 表示 max_stack 该方法执行的时候操作数栈最大的长度,这里表示操作数栈的长度为1
下面 2 个字节 0001 表示 max_locals 该方法局部变量所需要的空间的长度
下面 4 个字节 00 00 00 0B 表示code_length 即后面的 11 个字节为虚拟机字节码内容
代码的 11 个字节:2A B7 00 0A 2A 12 0C B5 00 0E B1
2A :aload_0 表示将第一个引用类型本地变量推送至栈顶
B7 :invokespecial 调用超类方法,后面的 000A,查看10号常量池 表示调用超类的init方法
2A :aload_0 表示将第一个引用类型本地变量推送至栈顶
12 :ldc 表示将一个常量池压入操作栈,后面的 0C 便是这个操作数,查看第13号常量池,为空
B5 :putfield 将操作栈的值赋给类变量,后面2个字节 000E 代表类变量的常量池索引,为 Ljava/lang/String; str
B1 : return ;返回void
这里我们可以知道类变量的初始化位置。
代码的 11 个字节以后
下面 2 个字节 0000 表示exception_table_length=0;也就是说没有异常处理
下面 2 个字节 0002 表示attributes_count=2,接下来有两个attribute_info 的结构
下面 2 个字节 0010 表示 attribute_name_index,查看10号常量池,为 LineNumberTable
下面 4 个字节 00 00 00 0E 表示attribute_length=14
下面 14 个字节是 LineNumberTable 的属性
下面 2 个字节 0011 表示 attribute_name_index,查看10号常量池,为 LocalVariableTable
下面 4 个字节 00 00 00 0C 表示attribute_length=12
下面 12 个字节是 LocalVariableTable 的属性
以上只是第一个方法的说明,后面的方法不再详细说明。
第五部分通常不是很重要,大概了解一下:
000002dbh: 00 01 00 27 00 00 00 02 00 28 ; ...'.....(
前面 2 个字节 0001 表示接下去有一个 attributes_info 结构,该结构占用 8 个字节
下面 2 个字节 0027 表示属性的名称的常量池索引,39 号常量的信息(属性的名称)为 SourceFile
下面 4 个字节 00000002 表示属性的长度,因为格式固定,所长度为 2
最后 2 个字节 0028 表示 sourcefile_index 的常量池索引, 40 号常量的信息(源文件的名称)为 PrintString.java
以上只是对一个结构简单的类作了一个简要说明,实际情况会复杂很多。详细内容大家可以参考《深入 Java 虚拟机(第二版)》
发表评论
-
windows 下配置 nginx + tomcat + memcached 集群
2014-06-11 16:33 1755前几天介绍了一下 memcached-session-filt ... -
让 memcached-session-filter 摆脱 spring 和 Java 序列化接口
2014-06-09 16:03 7100memcached-session-filter 项目是在 j ... -
关于 tomcat 集群中 session 共享的三种方法
2014-05-20 11:01 2283前两种均需要使用 memcached 或 redis 存储 ... -
简洁实用的免费的 FCKEditor 编辑器(2)
2014-04-09 09:18 1194前面已经下载了软件,并对于最基本的使用和支持文件上传讲了一下。 ... -
分布式版本管理 GIT 超酷教程
2014-04-08 09:09 610直接上链接: http://www.liaoxuefeng.c ... -
简洁实用的免费的 FCKEditor 编辑器(1)
2014-04-07 15:39 1679CKEditor 功能越来越强,界面也越来越靓,但收费总是让人 ... -
Eclipse 彻底禁用 JavaScript 验证
2014-04-05 13:34 1380我用的版本: Version: Indigo Service ... -
将旧版本的 eWebEditor 从 ASP 版改造为 JSP 版
2014-04-04 18:40 1722之前一个旧网站项目改版,发布系统的编辑器使用的 eWebEdi ... -
JavaRebel 关于 noverify 和 javaagent 参数的使用
2011-08-15 13:21 9032一般情况下,使用 JavaRebel 时都配置两个 JVM ... -
Eclipse 开发过程中利用 JavaRebel 提高效率
2011-08-13 09:43 1304Eclipse 是 Java 语言开发过程中的利器,相比较 M ... -
Mina 基本使用和常用类的介绍
2011-08-04 09:02 2218Mina 的全称是 Multipurpose ... -
FreeMarker 的两个应用实例
2011-07-18 12:26 2271FreeMarker 是一个 Java ... -
Java 的静态内部类使用
2011-07-11 11:02 1488Java 的内部类一般情况下很少使用,声明为 static 的 ... -
使用 UltraEdit 复制十六进制代码
2011-07-10 21:34 4331用UltraEdit 编辑文件时,常要用到查找、替换、复制和粘 ... -
深入学习 Lucene 3.0 索引段
2011-07-07 13:07 1969Lucene索引index由若干段(segment)组成,每一 ... -
Websphere MQ 学习笔记
2011-06-26 12:44 2386通信技术 MQI(Message Queue ... -
Java 程序的优化笔记
2011-06-15 08:59 1470系统的优化是一个比较宽泛的话题,涉及到硬件、软件和网络的优化等 ... -
XP 下 Java 本地接口调用 MinGW 编译的动态库
2011-06-13 13:26 1367Java 程序可以“一次编写,到处运行”,原因是它运行在 J ... -
JAVA 类中 serialVersionUID 的作用
2011-06-10 21:25 1339通常在继承 Serializable 接口的类,Eclips ... -
详解 Java 语言中 float 类型的运算
2011-06-08 13:56 5015【注】本文参考了网上的部分资料加上本人水平有限,存在错误在所 ...
相关推荐
1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? ...... 7 2、Java 有没有 goto? .......................................................................................................
53. 描述一下JVM加载class文件的原理机制? 30 54. socket编程 30 54.1. 什么是TCP/IP、UDP? 30 54.2. Socket在哪里呢? 31 54.3. Socket是什么呢? 32 54.4. socket的实现步骤 37 55. Servlet 38 55.1. Servlet工作...
75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器可以...
75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器可以...
75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器可以...
75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器可以...
75、描述一下JVM加载class文件的原理机制? 56 76、heap和stack有什么区别。 57 77、GC是什么? 为什么要有GC? 57 78、垃圾回收的优点和原理。并考虑2种回收机制。 57 79、垃圾回收器的基本原理是什么?垃圾回收器可以...
75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器可以...
75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器可以...
75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的优点和原理。并考虑2种回收机制。 52 79、垃圾回收器的基本原理是什么?垃圾回收器...
25.请详述在dotnet中类(class)与结构(struct)的异同? 答:Class可以被实例化,属于引用类型,是分配在内存的堆上的,Struct属于值类型,是分配在内存的栈上的. [Page] 26.根据委托(delegate)的知识,请完成以下用户...
2.1 .NET 结构.12 2.2 公用语言运行时环境与公用语言规范.13 2.3 开 发 工 具 .17 2.4 小 结 .19 第三章 编写第一个应用程序 .20 3.1 Welcome 程序 .20 3.2 代 码 分 析 .20 3.3 运 行 程 序 .23 .4...