- 浏览: 219459 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
hl174:
写的不错,赞一个
在Java中字节与十六进制的相互转换主要思想有两点 -
l540151663:
也是个好方法
String为空判断
java class文件结构2007年08月30日 星期四 下午 1:44
从上图中可以看到,一个 Java 类文件大致可以归为 10 个项:
Magic:该 项存放了一个 Java 类文件的魔数(magic number)和版本信息。一个 Java 类文件的前 4 个字节被称为它的魔数。每个正确的 Java 类文件都是以 0xCAFEBABE 开头的,这样保证了 Java 虚拟机能很轻松的分辨出 Java 文件和非 Java 文件。
Version:该项存放了 Java 类文件的版本信息,它对于一个 Java 文件具有重要的意义。因为 Java 技术一直在发展,所以类文件的格式也处在不断变化之中。类文件的版本信息让虚拟机知道如何去读取并处理该类文件。
Constant Pool:该 项存放了类中各种文字字符串、类名、方法名和接口名称、final 变量以及对外部类的引用信息等常量。虚拟机必须为每一个被装载的类维护一个常量池,常量池中存储了相应类型所用到的所有类型、字段和方法的符号引用,因此 它在 Java 的动态链接中起到了核心的作用。常量池的大,小,平均占到了整个类大小的 60% 左右。
Access_flag:该项指明了该文件中定义的是类还是接口(一个 class 文件中只能有一个类或接口),同时还指名了类或接口的访问标志,如 public,private, abstract 等信息。
This Class:指向表示该类全限定名称的字符串常量的指针。
Super Class:指向表示父类全限定名称的字符串常量的指针。
Interfaces:一个指针数组,存放了该类或父类实现的所有接口名称的字符串常量的指针。以上三项所指向的常量,特别是前两项,在我们用 ASM 从已有类派生新类时一般需要修改:将类名称改为子类名称;将父类改为派生前的类名称;如果有必要,增加新的实现接口。
Fields:该项对类或接口中声明的字段进行了细致的描述。需要注意的是,fields 列表中仅列出了本类或接口中的字段,并不包括从超类和父接口继承而来的字段。
Methods:该 项对类或接口中声明的方法进行了细致的描述。例如方法的名称、参数和返回值类型等。需要注意的是,methods 列表里仅存放了本类或本接口中的方法,并不包括从超类和父接口继承而来的方法。使用 ASM 进行 AOP 编程,通常是通过调整 Method 中的指令来实现的。
Class attributes:该项存放了在该文件中类或接口所定义的属性的基本信息。
以下转载自:http://edu.cryes.com/program/java/27962.html
Java文件结构用类似struct的描述如下:
ClassFile {
u4 magic; // 必须为: 0xCAFEBABE
u2 minor_version;
u2 major_version; //CLASS文件结构主次版本号 JAVA2支持45.0-46.0
u2 constant_pool_count; //记录常量信息
cp_info constant_pool[constant_pool_count-1]; //计数从1开始
u2 access_flags; //class/interface访问权限
u2 this_class; //指向constant_poll中的有效索引值
u2 super_class; //0或指向constant_poll中的有效索引值,对于interface必须为非0
u2 interfaces_count; //superinterfaces的个数
u2 interfaces[interfaces_count]; //计数[0,count-1) 对应constant_pool中的一个索引值
u2 fields_count;
field_info fields[fields_count]; //主要用于记录class及实例中的变量
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
cp_info {
u1 tag;
u1 info[];
}
tag 意义如下:
CONSTANT_Class 7 CONSTANT_Fieldref 9 CONSTANT_Methodref 10 CONSTANT_InterfaceMethodref 11 CONSTANT_String 8 CONSTANT_Integer 3 CONSTANT_Float 4 CONSTANT_Long 5 CONSTANT_Double 6 CONSTANT_NameAndType 12 CONSTANT_Utf8 1
此时cp_info分别对应结构变化为
1. CONSTANT_Class CONSTANT_Class_info { u1 tag; u2 name_index; } 2. CONSTANT_Fieldref CONSTANT_Fieldref_info { u1 tag; u2 class_index; //constant_pool的索引,对应CONSTANT_Class_info u2 name_and_type_index;//constant_pool的索引,对应CONSTANT_NameAndType_info } 3. CONSTANT_Methodref CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } 4. CONSTANT_InterfaceMethodref CONSTANT_InterfaceMethodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } 5. CONSTANT_String CONSTANT_String_info { u1 tag; u2 string_index; } 6. CONSTANT_Integer CONSTANT_Integer_info { u1 tag; u4 bytes; } 7. CONSTANT_Float CONSTANT_Float_info { u1 tag; u4 bytes; } 8. CONSTANT_Long CONSTANT_Long_info { u1 tag; u4 high_bytes; u4 low_bytes; } 9. CONSTANT_Double CONSTANT_Double_info { u1 tag; u4 high_bytes; u4 low_bytes } 10.CONSTANT_NameAndType CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; } 11.CONSTANT_Utf8 CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; }
access_flags意义如下:
ACC_PUBLIC 0x0001 ACC_FINAL 0x0010 ACC_SUPER 0x0020 ACC_INTERFACE 0x0200 ACC_ABSTRACT 0x0400
如果是interface那么必须置ACC_INTERFACE,如果没有置ACC_INTERFACE则定义的是一个类而非接口。
如果设置了ACC_INTERFACE,那么ACC_ABSTRACT位也必须被设置,当然也可以设置ACC_PUBLIC。
ACC_SUPER用以表明invokespecial语义,Sun公司老的JAVA编译器没有设置ACC_SUPER,并且老的JVM
忽略ACC_SUPER位,但新的编译器应该实现invokespecial语义。
其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。
this_class: constant_pool中的索引值,指向的元素的cp_info等价为CONSTANT_Class_info
CONSTANT_Class_info {
u1 tag; //必须为CONSTANT_Class (7)
u2 name_index; //为指向constant_pool中的一个索引值
}
name_index :指向的元素的cp_info等价为CONSTANT_Utf8_info
CONSTANT_Utf8_info {
u1 tag; //必须为CONSTANT_Utf8 (1)
u2 length;
u1 bytes[length]; //Utf8编码的字符串
}
field_info {
u2 access_flags; //访问控制权
u2 name_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
u2 descriptor_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
u2 attributes_count;
attribute_info attributes[attributes_count]; //attribute_info将在mothods后描述。
}
field_info中access_flages意义如下:
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_VOLATILE 0x0040
ACC_TRANSIENT 0x0080
其中很显然不能同时为ACC_FINAL和ACC_VOLATILE ;且前三项是互斥的。
interface必须置ACC_PUBLIC, ACC_STATIC,ACC_FINAL位,且不能置其他位。
其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。
methods指明了类中的所有方法。
method_info {
u2 access_flags;
u2 name_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info
u2 descriptor_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info
u2 attributes_count;
attribute_info attributes[attributes_count];
//此处只能出现Code、Exceptions、Synthetic、Deprecated四种类型的属性
}
access_flags访问权描述如下:
ACC_PUBLIC 0x0001 ACC_PRIVATE 0x0002 ACC_PROTECTED 0x0004 ACC_STATIC 0x0008 ACC_FINAL 0x0010 ACC_SYNCHRONIZED 0x0020 ACC_NATIVE 0x0100 ACC_ABSTRACT 0x0400 ACC_STRICT 0x0800
attribute_info {
u2 attribute_name_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
u4 attribute_length;
u1 info[attribute_length];
}
现在已经预定义的属性有:
1. SourceFile : attribute_info被替代为:
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index; //指向constant_pool中的一个CONSTANT_Utf8_info 结构。
}
2. ConstantValue : attribute_info被替代为:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length; //必须为2
u2 constantvalue_index;
}
对于constantvalue_index意义如下:
long CONSTANT_Long
float CONSTANT_Float
double CONSTANT_Double
int, short, char, byte, boolean CONSTANT_Integer
String CONSTANT_String
ConstantValue用于field_info 中,用于描述一个static常量,
且此时field_info的access_flags应为ACC_STATIC
3. Code : attribute_info被替代为:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack; //执行此函数时可用的栈的最大深度
u2 max_locals; //执行此函数可用到的最大本地变量数目,包括参数。
// 注意:一个long/double相当于2个变量数目.
u4 code_length; //本函数用到的代码长度。
u1 code[code_length]; //实现本函数的真正字节码
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc; //捕获违例时执行代码数组中的[start_pc, end_pc)部分
u2 handler_pc; //现在还不大明白他是干嘛的!!
u2 catch_type; //指向constant_pool的索引,对应CONSTANT_Class_info
}exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
CONSTANT_Class_info {
u1 tag; //必须为CONSTANT_Class (7)
u2 name_index; //不用我再说了吧?
}
Code属性用于method_info结构中。
4. Exceptions : attribute_info被替代为:
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
5. InnerClasses : attribute_info被替代为:
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;
u2 outer_class_info_index;
u2 inner_name_index;
u2 inner_class_access_flags;
} classes[number_of_classes];
}
6. Synthetic : attribute_info被替代为:
Synthetic_attribute {
u2 attribute_name_index; //不用废话了吧?
u4 attribute_length; //必须为0
}
Synthetic用在 field_info、 method_info 中,
一个没有出现在源程序中的变量必须使用Synthetic标记。
7. LineNumberTable : attribute_info被替代为:
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];
}
LineNumberTable用于Code属性中,通常用于调试。
8. LocalVariableTable : attribute_info被替代为:
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length; //当解释到代码数组的[start_pc,start_pc+length]
//时变量必须被赋值??
u2 name_index;
u2 descriptor_index;
u2 index; //到本地变量数组的一个索引
} local_variable_table[local_variable_table_length];
}
9. Deprecated : attribute_info被替代为:
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length; //必须为0
}
当然你也可以定义自己的属性,但要你自己的编译器和虚拟机实现。JVM将忽略自己不认可的属性。
来实践一下吧!
编写一个最简单的程序:
class Test
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
c:\work>javac Test.java
c:\work>filedump Test.class
File Dump V0.3 Beta by cloud (safesuite@363.net).
01:00 ca fe ba be 00 03 00 2d 00 1d 0a 00 06 00 0f 09 .......-........
01:01 00 10 00 11 08 00 12 0a 00 13 00 14 07 00 15 07 ................
01:02 00 16 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 .....<init>...()
01:03 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e V...Code...LineN
01:04 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69 umberTable...mai
01:05 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 n...([Ljava/lang
01:06 2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75 /String;)V...Sou
01:07 72 63 65 46 69 6c 65 01 00 09 54 65 73 74 2e 6a rceFile...Test.j
>d
02:00 61 76 61 0c 00 07 00 08 07 00 17 0c 00 18 00 19 ava.............
02:01 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 07 ...Hello World!.
02:02 00 1a 0c 00 1b 00 1c 01 00 04 54 65 73 74 01 00 ..........Test..
02:03 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 .java/lang/Objec
02:04 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 t...java/lang/Sy
02:05 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 stem...out...Lja
02:06 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 va/io/PrintStrea
02:07 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 m;...java/io/Pri
>d
03:00 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e 74 ntStream...print
03:01 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 ln...(Ljava/lang
03:02 2f 53 74 72 69 6e 67 3b 29 56 00 20 00 05 00 06 /String;)V. ....
03:03 00 00 00 00 00 02 00 00 00 07 00 08 00 01 00 09 ................
03:04 00 00 00 1d 00 01 00 01 00 00 00 05 2a b7 00 01 ............*...
03:05 b1 00 00 00 01 00 0a 00 00 00 06 00 01 00 00 00 ................
03:06 01 00 09 00 0b 00 0c 00 01 00 09 00 00 00 25 00 ..............%.
03:07 02 00 01 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 ................
>d
04:00 00 00 00 01 00 0a 00 00 00 0a 00 02 00 00 00 05 ................
04:01 00 08 00 06 00 01 00 0d 00 00 00 02 00 0e ..............
>
解读一下:
ca fe ba be magic
00 03 00 2d 次主版本号,换算一下: 45.3 (注意,不是高字节在前,别犯职业病!)
00 1d constant_pool元素个数加一 : 29 那么constant_pool就是[1-28]
constant_pool: 1-28
1. 0a 00 06 00 0f
0x0a :CONSTANT_InterfaceMethodref 0x06 :class index 0x0f :name-type-index
2. 09 00 10 00 11
0x09 : CONSTANT_Fieldref 0x10: . . . 0x11 : . . . .
3. 08 00 12 0x08 : CONSTANT_String 0x12 : string_index
4. 0a 00 13 00 14 0x0a同于1.
5. 07 00 15 0x07 : CONSTANT_Class 0x15 : name_index
6. 07 00 16
7. 01 00 06 3c 69 6e 69 74 3e 01 ...<init>
0x01 CONSTANT_Utf8 0x06 : string length "<init>" : 构造函数
8. 01 00 03 28 29 56 ...()V 函数,无参数
0x01 . . . . . . 0x03 : . . . . "()V" : . . .
9. 01 00 04 43 6f 64 65 ...Code
10. 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 ...LineNumberTable
11. 01 00 04 6d 61 69 6e ...main
12. 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
...([Ljava/lang/String;)
V 函数,参数为String[]类型
13. 01 00 0a 53 6f 75 72 63 65 46 69 6c 65 ...SourceFile
14. 01 00 09 54 65 73 74 2e 6a 61 76 61 ...Test.java
15. 0c 00 07 00 08 0x0c:CONSTANT_NameAndType 07 : name-index 08:name-type-index
16. 07 00 17
17. 0c 00 18 00 19
18. 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 ...Hello World!
19. 07 00 1a
20. 0c 00 1b 00 1c
21. 01 00 04 54 65 73 74 ...Test
22. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 ...java/lang/Object
23. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d ...java/lang/System
24. 01 00 03 6f 75 74 ...out
25. 01 00 15 4c 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b
...Ljava/io/PrintStream;
26. 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d...java/io/PrintStream
27. 01 00 07 70 72 69 6e 74 6c 6e ...println
28. 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
...(Ljava/lang/String;)V
00 20 access_flags
00 05 this_class
00 06 super_class
00 00 interfaces_count
00 00 fields_count
00 02 methods_count
methods[2]:
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
0. 00 00 access_flags;
00 07 name_index; 看看constant_pool的第7项: <init> 表明当前描述构造函数
00 08 descriptor_index;
00 01 attributes_count;
00 09 attribute_name_index 0x09 看看constant_pool的第9项,简单明了Code !!
00 00 00 1d attribute_length = 29
00 01 max_stack
00 01 max_locals
00 00 00 05 code_length
2a b7 00 01 b1 JVM定义的操作码代码段数组
00 00 exception_table_length
00 01 attributes_count 一个,接下来是attribute_info结构
00 0a attribute_name_index 看看constant_pool的第10项: LineNumberTable(显然调试用)
00 00 00 06 attribute_length
00 01 line_number_table_length
00 00 start_pc
00 01 line_number
1. 00 09 access_flags PUBLIC & STATIC
00 0b name_index; 表明当前描述main函数
00 0c descriptor_index; ...([Ljava/lang/String;)V
00 01 attributes_count;
00 09 attribute_name_index Code
00 00 00 25 attribute_length = 37
00 02 max_stack
00 01 max_locals
00 00 00 09 code_length
b2 00 02 12 03 b6 00 04 b1 代码数组 codeArray1[0-8]
00 00 exception_table_length
00 01 attributes_count 接下来是attribute_info结构
00 0a attribute_name_index LineNumberTable
00 00 00 0a attribute_length
00 02 line_number_table_length
00 00 start_pc
00 05 line_number
00 08 start_pc : codeArray1[8] = 0xb1 --> return
00 06 line_number 第6行源程序为 }
00 01 attributes_count
00 0d attribute_name_index 属性为SourceFile
00 00 00 02 attribute_length
00 0e sourcefile_index constant_pool[0x0e] --- > "Test.java"
接下来我们看看main()函数对应的代码:
b2 00 02 12 03 b6 00 04 b1
0xb2 0x00 0x02 : getstatic #2
看看constant_pool[0x02] :09 00 10 00 11
0x09 : CONSTANT_Fieldref 0x10: class index 0x11 :name-type-index
constant_pool[0x10]: --> constant_pool[0x17] : java/lang/System
constant_pool[0x11]: 0x18 : class index 0x19 :name-type-index
constant_pool[0x18] : out
constant_pool[0x19] : Ljava/io/PrintStream
即 System.out 为 java.io.PrintStream 类型
0x12 0x03 : ldc #3
看看 constant_pool[3] : 08 00 12 0x08 : CONSTANT_String 0x12 : string_index
指向一个字符串 constant_pool[0x12]: "Hello World!"
故该指令加载了字符串索引到本地栈
0xb6 0x00 0x04: invokevirtual #4
------->到constant_pool查查 0x13 :class 0x14 :name-type
看看constant_pool[0x13]:java/io/PrintStream
constant_pool[20] :--> 00 1b 00 1c
constant_pool[0x1b]:println
. . . .Ljava/lang/String;)V
故该指令调用了 java.io.PrintStream.println(java.lang.String)
而参数则为 ldc #3 加载的 "Hello World!"
0xb1 : return
从上图中可以看到,一个 Java 类文件大致可以归为 10 个项:
Magic:该 项存放了一个 Java 类文件的魔数(magic number)和版本信息。一个 Java 类文件的前 4 个字节被称为它的魔数。每个正确的 Java 类文件都是以 0xCAFEBABE 开头的,这样保证了 Java 虚拟机能很轻松的分辨出 Java 文件和非 Java 文件。
Version:该项存放了 Java 类文件的版本信息,它对于一个 Java 文件具有重要的意义。因为 Java 技术一直在发展,所以类文件的格式也处在不断变化之中。类文件的版本信息让虚拟机知道如何去读取并处理该类文件。
Constant Pool:该 项存放了类中各种文字字符串、类名、方法名和接口名称、final 变量以及对外部类的引用信息等常量。虚拟机必须为每一个被装载的类维护一个常量池,常量池中存储了相应类型所用到的所有类型、字段和方法的符号引用,因此 它在 Java 的动态链接中起到了核心的作用。常量池的大,小,平均占到了整个类大小的 60% 左右。
Access_flag:该项指明了该文件中定义的是类还是接口(一个 class 文件中只能有一个类或接口),同时还指名了类或接口的访问标志,如 public,private, abstract 等信息。
This Class:指向表示该类全限定名称的字符串常量的指针。
Super Class:指向表示父类全限定名称的字符串常量的指针。
Interfaces:一个指针数组,存放了该类或父类实现的所有接口名称的字符串常量的指针。以上三项所指向的常量,特别是前两项,在我们用 ASM 从已有类派生新类时一般需要修改:将类名称改为子类名称;将父类改为派生前的类名称;如果有必要,增加新的实现接口。
Fields:该项对类或接口中声明的字段进行了细致的描述。需要注意的是,fields 列表中仅列出了本类或接口中的字段,并不包括从超类和父接口继承而来的字段。
Methods:该 项对类或接口中声明的方法进行了细致的描述。例如方法的名称、参数和返回值类型等。需要注意的是,methods 列表里仅存放了本类或本接口中的方法,并不包括从超类和父接口继承而来的方法。使用 ASM 进行 AOP 编程,通常是通过调整 Method 中的指令来实现的。
Class attributes:该项存放了在该文件中类或接口所定义的属性的基本信息。
以下转载自:http://edu.cryes.com/program/java/27962.html
Java文件结构用类似struct的描述如下:
ClassFile {
u4 magic; // 必须为: 0xCAFEBABE
u2 minor_version;
u2 major_version; //CLASS文件结构主次版本号 JAVA2支持45.0-46.0
u2 constant_pool_count; //记录常量信息
cp_info constant_pool[constant_pool_count-1]; //计数从1开始
u2 access_flags; //class/interface访问权限
u2 this_class; //指向constant_poll中的有效索引值
u2 super_class; //0或指向constant_poll中的有效索引值,对于interface必须为非0
u2 interfaces_count; //superinterfaces的个数
u2 interfaces[interfaces_count]; //计数[0,count-1) 对应constant_pool中的一个索引值
u2 fields_count;
field_info fields[fields_count]; //主要用于记录class及实例中的变量
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
cp_info {
u1 tag;
u1 info[];
}
tag 意义如下:
CONSTANT_Class 7 CONSTANT_Fieldref 9 CONSTANT_Methodref 10 CONSTANT_InterfaceMethodref 11 CONSTANT_String 8 CONSTANT_Integer 3 CONSTANT_Float 4 CONSTANT_Long 5 CONSTANT_Double 6 CONSTANT_NameAndType 12 CONSTANT_Utf8 1
此时cp_info分别对应结构变化为
1. CONSTANT_Class CONSTANT_Class_info { u1 tag; u2 name_index; } 2. CONSTANT_Fieldref CONSTANT_Fieldref_info { u1 tag; u2 class_index; //constant_pool的索引,对应CONSTANT_Class_info u2 name_and_type_index;//constant_pool的索引,对应CONSTANT_NameAndType_info } 3. CONSTANT_Methodref CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } 4. CONSTANT_InterfaceMethodref CONSTANT_InterfaceMethodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } 5. CONSTANT_String CONSTANT_String_info { u1 tag; u2 string_index; } 6. CONSTANT_Integer CONSTANT_Integer_info { u1 tag; u4 bytes; } 7. CONSTANT_Float CONSTANT_Float_info { u1 tag; u4 bytes; } 8. CONSTANT_Long CONSTANT_Long_info { u1 tag; u4 high_bytes; u4 low_bytes; } 9. CONSTANT_Double CONSTANT_Double_info { u1 tag; u4 high_bytes; u4 low_bytes } 10.CONSTANT_NameAndType CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; } 11.CONSTANT_Utf8 CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; }
access_flags意义如下:
ACC_PUBLIC 0x0001 ACC_FINAL 0x0010 ACC_SUPER 0x0020 ACC_INTERFACE 0x0200 ACC_ABSTRACT 0x0400
如果是interface那么必须置ACC_INTERFACE,如果没有置ACC_INTERFACE则定义的是一个类而非接口。
如果设置了ACC_INTERFACE,那么ACC_ABSTRACT位也必须被设置,当然也可以设置ACC_PUBLIC。
ACC_SUPER用以表明invokespecial语义,Sun公司老的JAVA编译器没有设置ACC_SUPER,并且老的JVM
忽略ACC_SUPER位,但新的编译器应该实现invokespecial语义。
其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。
this_class: constant_pool中的索引值,指向的元素的cp_info等价为CONSTANT_Class_info
CONSTANT_Class_info {
u1 tag; //必须为CONSTANT_Class (7)
u2 name_index; //为指向constant_pool中的一个索引值
}
name_index :指向的元素的cp_info等价为CONSTANT_Utf8_info
CONSTANT_Utf8_info {
u1 tag; //必须为CONSTANT_Utf8 (1)
u2 length;
u1 bytes[length]; //Utf8编码的字符串
}
field_info {
u2 access_flags; //访问控制权
u2 name_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
u2 descriptor_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
u2 attributes_count;
attribute_info attributes[attributes_count]; //attribute_info将在mothods后描述。
}
field_info中access_flages意义如下:
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_VOLATILE 0x0040
ACC_TRANSIENT 0x0080
其中很显然不能同时为ACC_FINAL和ACC_VOLATILE ;且前三项是互斥的。
interface必须置ACC_PUBLIC, ACC_STATIC,ACC_FINAL位,且不能置其他位。
其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。
methods指明了类中的所有方法。
method_info {
u2 access_flags;
u2 name_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info
u2 descriptor_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info
u2 attributes_count;
attribute_info attributes[attributes_count];
//此处只能出现Code、Exceptions、Synthetic、Deprecated四种类型的属性
}
access_flags访问权描述如下:
ACC_PUBLIC 0x0001 ACC_PRIVATE 0x0002 ACC_PROTECTED 0x0004 ACC_STATIC 0x0008 ACC_FINAL 0x0010 ACC_SYNCHRONIZED 0x0020 ACC_NATIVE 0x0100 ACC_ABSTRACT 0x0400 ACC_STRICT 0x0800
attribute_info {
u2 attribute_name_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
u4 attribute_length;
u1 info[attribute_length];
}
现在已经预定义的属性有:
1. SourceFile : attribute_info被替代为:
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index; //指向constant_pool中的一个CONSTANT_Utf8_info 结构。
}
2. ConstantValue : attribute_info被替代为:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length; //必须为2
u2 constantvalue_index;
}
对于constantvalue_index意义如下:
long CONSTANT_Long
float CONSTANT_Float
double CONSTANT_Double
int, short, char, byte, boolean CONSTANT_Integer
String CONSTANT_String
ConstantValue用于field_info 中,用于描述一个static常量,
且此时field_info的access_flags应为ACC_STATIC
3. Code : attribute_info被替代为:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack; //执行此函数时可用的栈的最大深度
u2 max_locals; //执行此函数可用到的最大本地变量数目,包括参数。
// 注意:一个long/double相当于2个变量数目.
u4 code_length; //本函数用到的代码长度。
u1 code[code_length]; //实现本函数的真正字节码
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc; //捕获违例时执行代码数组中的[start_pc, end_pc)部分
u2 handler_pc; //现在还不大明白他是干嘛的!!
u2 catch_type; //指向constant_pool的索引,对应CONSTANT_Class_info
}exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
CONSTANT_Class_info {
u1 tag; //必须为CONSTANT_Class (7)
u2 name_index; //不用我再说了吧?
}
Code属性用于method_info结构中。
4. Exceptions : attribute_info被替代为:
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
5. InnerClasses : attribute_info被替代为:
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;
u2 outer_class_info_index;
u2 inner_name_index;
u2 inner_class_access_flags;
} classes[number_of_classes];
}
6. Synthetic : attribute_info被替代为:
Synthetic_attribute {
u2 attribute_name_index; //不用废话了吧?
u4 attribute_length; //必须为0
}
Synthetic用在 field_info、 method_info 中,
一个没有出现在源程序中的变量必须使用Synthetic标记。
7. LineNumberTable : attribute_info被替代为:
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];
}
LineNumberTable用于Code属性中,通常用于调试。
8. LocalVariableTable : attribute_info被替代为:
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc;
u2 length; //当解释到代码数组的[start_pc,start_pc+length]
//时变量必须被赋值??
u2 name_index;
u2 descriptor_index;
u2 index; //到本地变量数组的一个索引
} local_variable_table[local_variable_table_length];
}
9. Deprecated : attribute_info被替代为:
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length; //必须为0
}
当然你也可以定义自己的属性,但要你自己的编译器和虚拟机实现。JVM将忽略自己不认可的属性。
来实践一下吧!
编写一个最简单的程序:
class Test
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
c:\work>javac Test.java
c:\work>filedump Test.class
File Dump V0.3 Beta by cloud (safesuite@363.net).
01:00 ca fe ba be 00 03 00 2d 00 1d 0a 00 06 00 0f 09 .......-........
01:01 00 10 00 11 08 00 12 0a 00 13 00 14 07 00 15 07 ................
01:02 00 16 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 .....<init>...()
01:03 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e V...Code...LineN
01:04 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69 umberTable...mai
01:05 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 n...([Ljava/lang
01:06 2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75 /String;)V...Sou
01:07 72 63 65 46 69 6c 65 01 00 09 54 65 73 74 2e 6a rceFile...Test.j
>d
02:00 61 76 61 0c 00 07 00 08 07 00 17 0c 00 18 00 19 ava.............
02:01 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 07 ...Hello World!.
02:02 00 1a 0c 00 1b 00 1c 01 00 04 54 65 73 74 01 00 ..........Test..
02:03 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 .java/lang/Objec
02:04 74 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 t...java/lang/Sy
02:05 73 74 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 stem...out...Lja
02:06 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 va/io/PrintStrea
02:07 6d 3b 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 m;...java/io/Pri
>d
03:00 6e 74 53 74 72 65 61 6d 01 00 07 70 72 69 6e 74 ntStream...print
03:01 6c 6e 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 ln...(Ljava/lang
03:02 2f 53 74 72 69 6e 67 3b 29 56 00 20 00 05 00 06 /String;)V. ....
03:03 00 00 00 00 00 02 00 00 00 07 00 08 00 01 00 09 ................
03:04 00 00 00 1d 00 01 00 01 00 00 00 05 2a b7 00 01 ............*...
03:05 b1 00 00 00 01 00 0a 00 00 00 06 00 01 00 00 00 ................
03:06 01 00 09 00 0b 00 0c 00 01 00 09 00 00 00 25 00 ..............%.
03:07 02 00 01 00 00 00 09 b2 00 02 12 03 b6 00 04 b1 ................
>d
04:00 00 00 00 01 00 0a 00 00 00 0a 00 02 00 00 00 05 ................
04:01 00 08 00 06 00 01 00 0d 00 00 00 02 00 0e ..............
>
解读一下:
ca fe ba be magic
00 03 00 2d 次主版本号,换算一下: 45.3 (注意,不是高字节在前,别犯职业病!)
00 1d constant_pool元素个数加一 : 29 那么constant_pool就是[1-28]
constant_pool: 1-28
1. 0a 00 06 00 0f
0x0a :CONSTANT_InterfaceMethodref 0x06 :class index 0x0f :name-type-index
2. 09 00 10 00 11
0x09 : CONSTANT_Fieldref 0x10: . . . 0x11 : . . . .
3. 08 00 12 0x08 : CONSTANT_String 0x12 : string_index
4. 0a 00 13 00 14 0x0a同于1.
5. 07 00 15 0x07 : CONSTANT_Class 0x15 : name_index
6. 07 00 16
7. 01 00 06 3c 69 6e 69 74 3e 01 ...<init>
0x01 CONSTANT_Utf8 0x06 : string length "<init>" : 构造函数
8. 01 00 03 28 29 56 ...()V 函数,无参数
0x01 . . . . . . 0x03 : . . . . "()V" : . . .
9. 01 00 04 43 6f 64 65 ...Code
10. 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 ...LineNumberTable
11. 01 00 04 6d 61 69 6e ...main
12. 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
...([Ljava/lang/String;)
V 函数,参数为String[]类型
13. 01 00 0a 53 6f 75 72 63 65 46 69 6c 65 ...SourceFile
14. 01 00 09 54 65 73 74 2e 6a 61 76 61 ...Test.java
15. 0c 00 07 00 08 0x0c:CONSTANT_NameAndType 07 : name-index 08:name-type-index
16. 07 00 17
17. 0c 00 18 00 19
18. 01 00 0c 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 ...Hello World!
19. 07 00 1a
20. 0c 00 1b 00 1c
21. 01 00 04 54 65 73 74 ...Test
22. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 ...java/lang/Object
23. 01 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d ...java/lang/System
24. 01 00 03 6f 75 74 ...out
25. 01 00 15 4c 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b
...Ljava/io/PrintStream;
26. 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d...java/io/PrintStream
27. 01 00 07 70 72 69 6e 74 6c 6e ...println
28. 01 00 15 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 56
...(Ljava/lang/String;)V
00 20 access_flags
00 05 this_class
00 06 super_class
00 00 interfaces_count
00 00 fields_count
00 02 methods_count
methods[2]:
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
0. 00 00 access_flags;
00 07 name_index; 看看constant_pool的第7项: <init> 表明当前描述构造函数
00 08 descriptor_index;
00 01 attributes_count;
00 09 attribute_name_index 0x09 看看constant_pool的第9项,简单明了Code !!
00 00 00 1d attribute_length = 29
00 01 max_stack
00 01 max_locals
00 00 00 05 code_length
2a b7 00 01 b1 JVM定义的操作码代码段数组
00 00 exception_table_length
00 01 attributes_count 一个,接下来是attribute_info结构
00 0a attribute_name_index 看看constant_pool的第10项: LineNumberTable(显然调试用)
00 00 00 06 attribute_length
00 01 line_number_table_length
00 00 start_pc
00 01 line_number
1. 00 09 access_flags PUBLIC & STATIC
00 0b name_index; 表明当前描述main函数
00 0c descriptor_index; ...([Ljava/lang/String;)V
00 01 attributes_count;
00 09 attribute_name_index Code
00 00 00 25 attribute_length = 37
00 02 max_stack
00 01 max_locals
00 00 00 09 code_length
b2 00 02 12 03 b6 00 04 b1 代码数组 codeArray1[0-8]
00 00 exception_table_length
00 01 attributes_count 接下来是attribute_info结构
00 0a attribute_name_index LineNumberTable
00 00 00 0a attribute_length
00 02 line_number_table_length
00 00 start_pc
00 05 line_number
00 08 start_pc : codeArray1[8] = 0xb1 --> return
00 06 line_number 第6行源程序为 }
00 01 attributes_count
00 0d attribute_name_index 属性为SourceFile
00 00 00 02 attribute_length
00 0e sourcefile_index constant_pool[0x0e] --- > "Test.java"
接下来我们看看main()函数对应的代码:
b2 00 02 12 03 b6 00 04 b1
0xb2 0x00 0x02 : getstatic #2
看看constant_pool[0x02] :09 00 10 00 11
0x09 : CONSTANT_Fieldref 0x10: class index 0x11 :name-type-index
constant_pool[0x10]: --> constant_pool[0x17] : java/lang/System
constant_pool[0x11]: 0x18 : class index 0x19 :name-type-index
constant_pool[0x18] : out
constant_pool[0x19] : Ljava/io/PrintStream
即 System.out 为 java.io.PrintStream 类型
0x12 0x03 : ldc #3
看看 constant_pool[3] : 08 00 12 0x08 : CONSTANT_String 0x12 : string_index
指向一个字符串 constant_pool[0x12]: "Hello World!"
故该指令加载了字符串索引到本地栈
0xb6 0x00 0x04: invokevirtual #4
------->到constant_pool查查 0x13 :class 0x14 :name-type
看看constant_pool[0x13]:java/io/PrintStream
constant_pool[20] :--> 00 1b 00 1c
constant_pool[0x1b]:println
. . . .Ljava/lang/String;)V
故该指令调用了 java.io.PrintStream.println(java.lang.String)
而参数则为 ldc #3 加载的 "Hello World!"
0xb1 : return
发表评论
-
Connected to the target VM, address: '127.0.0.1:52445', transport: 'socket' 错误:
2018-01-16 17:23 4701把 C:\Program Files (x86)\JetBra ... -
activemq Unrecognized Windows Sockets error: 10106: Socket creation failed
2018-01-16 17:27 85730-Nov-2017 22:45:52.892 严重 [ma ... -
Twitter的分布式自增ID算法snowflake (Java版)
2017-04-06 10:59 474概述 分布式系统中, ... -
gd总结20170104
2017-01-04 12:13 3031:tree获取选中的值,天窗项目-告警列表 $(functi ... -
java调优20161229
2016-12-29 20:03 4041:尽量减少对变量的重复计算 明确一个概念,对方法的调用,即 ... -
java2,8,10,16进制转换
2016-12-19 19:34 460A、十进制转换其他 十进制转成二进制 Integ ... -
java 修饰符
2016-12-06 22:20 372Java中共有四种访问限制修饰符:private,public ... -
java集合总结20161203
2016-12-03 15:26 4931:list 有序集合,元素 ... -
java常用集合总结
2016-12-03 14:55 495java常用集合总结 1、线程安全 线程安全就是说多线程访 ... -
设计模式总结1
2016-12-03 14:50 5541:像上转型================= 1.1定义抽象 ... -
pinyin4j
2016-12-02 15:40 367package cn.com.iotrust.common.u ... -
java IO流学习总结
2016-11-11 17:54 428Java中的流,可以从不同 ... -
JAVA泛型
2016-11-08 23:00 502泛型就是变量类型的参数化。在使用泛型前,存入集合中的元素可以是 ... -
Java常见集合的归纳总结
2016-11-08 21:58 461Java常见集合的归纳总结 首先来看看集合的关系: C ... -
maven总结20160925
2016-09-25 09:45 6451:安装后查看maven版本 mvn -version(或者 ... -
HTTP请求原理介绍
2016-09-20 19:19 581HTTP(HyperText Transfer Protoco ... -
post和get的区别
2016-09-10 22:35 3981. get是从服务器上获取数据,post是向服务器传送数据。 ... -
mysql 生成一个临时日历表
2016-08-26 13:32 920begin declare indexdate DATE; s ... -
tomcat内存设置
2016-08-18 17:46 337tomcat内存设置 -------------------- ... -
页面图表显示
2016-08-05 11:15 5261:百度echarts http://echarts.baid ...
相关推荐
1、打开一个或者多个*.class文件,XJad反编译后,重命名为*.java文件, 保存至当前文件夹,并在编辑器中打开查看; 2、打开一个文件夹,XJad将该文件夹下所有*.class文件进行反编译,并保存至该文件夹下, 依据包...
java class的文件结构,java class文件结构是基于字节流的,用unicode进行编码,下面说说java Class文件内部结构分析
JavaClassViewer-2.0.4, 用于理解Class文件结构。 解析出class结构,以及十六进制的表示,特别方便。 原下载地址: http://www.softpedia.com/get/Programming/File-Editors/Java-Class-Viewer.shtml。另外也可以参考...
上海计算所分析的关于java字节码的结构组成
这个是个压缩包,里面包含了从各个地方收集来的关于JAVA_CLASS的文件结构的分析。东西都不是我的,自然也不敢说收版权费。所以就小小地收收体力费好了。...(内含五篇,包括:《JavaClass文件的结构分析及其校验》)
JavaClass文件加密专家通过分析Class文件的结构,将Class二进制代码中耗时较多的部份抽出并替换为Native C代码, 并且使用1024位加密算法将Class文件数据加密,任何Java反编译工具均不可能对加密后的文件...
Java虚拟机中的class类文件的知识,个人整理大的class类文件结构.xmind,有什么问题及时反馈。
java Class文件分析及其解析执行是分析JVM的重要部分,通过实例对Class文件的结构进行了详细分析,并初步实现了Class文件的解析执行。
java反编译项目工程,可以将class 文件 进行 修改 重新导包 生成修改后的jar 步骤 1、将需要修改的 jar 包 放入 lib 目录下,并加入项目中 ,选中 jar 右击 选择 add a libray这个时候会看到 jar 的 目录 结构 2、...
一个简单的分析工具,用于分析”.class/.cap/.exp”格式的Java文件。 对于CAP文件,支持version 2.1 and 2.2. 适用于JCVM的学习。 使用工具时,需保证“C:\Program Files\WinZip\WINZIP32.EXE”存在,用于解压CAP...
今天把之前在Evernote中的笔记重新整理了一下,发上来供对java class 文件结构的有兴趣的同学参考一下
我们都知道,Java程序最终是转换成class文件执行在虚拟机上的,那么class文件是个怎样的结构,虚拟机又是如何处理去执行class文件里面的内容呢,这篇文章带你深入理解Java字节码中的结构。 1.Demo源码 首先,编写一...
}属性属性(Attributes)在 Class 文件格式中的 ClassFile结构、 field_info结构,method_info结构和 Code_at
以思维导图的方式概括了java class文件的结构。其中用位置描述了各个结构出现的顺序。为JVM的一个分支。
class文件是由8bits的字节流组成,全部字节构成了15个有意义...随着Java技术的发展,class文件的格式会发生变化。版本号的作用在于使得虚拟机能够认识当前加载class的文件格式。从而准确的提取class文件信息。 3.co
了解Class文件的结构组成,对于我们后续的JVM以及Java原理深入学习是很有帮助的,因为Class文件帮我们默默的做了很多事,比如、为什么对象方法中可以直接使用this变量?!本文将带领大家,一步步,从开头到结尾,...
java反编译工具,能把.class的文件 编译成.java的文件,在开发中用到的一些第三方插件包的时候,也许你想看看其内部结构怎么写的,就可以把.jar 的转换成.java来看,很好的
Class文件结构明细,各种详细的指标,以java1.8版本为例。
NULL 博文链接:https://bolinyang.iteye.com/blog/1830472