简单梳理下class文件格式,以及如何手动对class常量池进行修改<待续>
参考资料:《Java Virtual Machine Specification Java SE 7》
ClassFile {
u4 magic; //始终是0xCAFEBABE
u2 minor_version; // 次版本号
u2 major_version; // 主版本号
u2 constant_pool_count; // 常量数
cp_info constant_pool[constant_pool_count-1]; // 常量池,索引从1开始计数
u2 access_flags; // 访问权限标志,如public
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]; //属性信息
}
其中:access_flags参数集合
标记名 | 值 | 含义 |
---|---|---|
ACC_PUBLIC | 0x0001 | 可以被包的类外访问。 |
ACC_FINAL | 0x0010 | 不允许有子类。 |
ACC_SUPER | 0x0020 | 当用到 invokespecial 指令时,需要特殊处理的父类方法。 |
ACC_INTERFACE | 0x0200 | 标识定义的是接口而不是类。 |
ACC_ABSTRACT | 0x0400 | 不能被实例化。 |
ACC_SYNTHETIC | 0x1000 | 标识并非 Java 源码生成的代码。 |
ACC_ANNOTATION | 0x2000 | 标识注解类型 |
ACC_ENUM | 0x4000 | 标识枚举类型 |
cp_info的具体定义
CONSTANT_Class_info {
u1 tag; // 类型标记
u2 name_index; // 类名索引,指向CONSTANT_Utf8_info
}
CONSTANT_Fieldref_info {
u1 tag; // 类型标记
u2 class_index; // 所属类索引,指向CONSTANT_Class_info
u2 name_and_type_index; // 类型索引,指向CONSTANT_NameAndType_info
}
CONSTANT_Methodref_info {
u1 tag; // 类型标记
u2 class_index; // 所属类索引,指向CONSTANT_Class_info
u2 name_and_type_index; // 引用类型索引,指向CONSTANT_NameAndType_info
}
CONSTANT_InterfaceMethodref_info {
u1 tag; // 类型标记
u2 class_index; // 所属类索引,指向CONSTANT_Class_info
u2 name_and_type_index; // 引用类型索引,指向CONSTANT_NameAndType_info
}
CONSTANT_String_info {
u1 tag; // 类型标记
u2 string_index; // 类名索引索引,指向CONSTANT_Utf8_info
}
CONSTANT_Integer_info {
u1 tag; // 类型标记
u4 bytes; // 大端格式32位,带符号位
}
CONSTANT_Float_info {
u1 tag; // 类型标记
u4 bytes; // 大端格式32位,带符号位
}
CONSTANT_Long_info {
u1 tag; // 类型标记
u4 high_bytes; // 高32位
u4 low_bytes; // 低32位
}
CONSTANT_Double_info {
u1 tag; // 类型标记
u4 high_bytes; // 高32位
u4 low_bytes; // 低32位
}
CONSTANT_NameAndType_info {
u1 tag; // 类型标记
u2 name_index; //特殊的方法名<init>、字段或方法的非限定名索引,指向CONSTANT_Utf8_info
u2 descriptor_index; //字段描述符、方法描述符索引,指向CONSTANT_Utf8_info
}
CONSTANT_Utf8_info {
u1 tag; // 类型标记
u2 length; // 字符串长度
u1 bytes[length]; // 字节数组
}
CONSTANT_MethodHandle_info {
u1 tag; // 类型标记
u1 reference_kind; // 方法句柄
u2 reference_index; // 引用索引,指向CONSTANT_Fieldref_info、CONSTANT_Methodref_info或CONSTANT_InterfaceMethodref_info,根据reference_kind而定
}
CONSTANT_MethodType_info {
u1 tag; // 类型标记
u2 descriptor_index; // 方法描述符索引,指向CONSTANT_Utf8_info
}
CONSTANT_InvokeDynamic_info {
u1 tag; // 类型标记
u2 bootstrap_method_attr_index; // 当前Class文件中引导方法表索引
u2 name_and_type_index; // 方法名和方法描述,指向CONSTANT_NameAndType_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 |
CONSTANT_MethodHandle | 15 |
CONSTANT_MethodType | 16 |
CONSTANT_InvokeDynamic | 18 |
字段定义
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
方法定义
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
attribute_info 具体定义
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
StackMapTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_entries;
stack_map_frame entries[number_of_entries];
}
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions];
}
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];
}
EnclosingMethod_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 class_index
u2 method_index;
}
Synthetic_attribute {
u2 attribute_name_index;
u4 attribute_length;
}
Signature_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 signature_index;
}
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 sourcefile_index;
}
SourceDebugExtension_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 debug_extension[attribute_length];
}
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_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];
}
LocalVariableTypeTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_type_table_length;
{ u2 start_pc;
u2 length;
u2 name_index;
u2 signature_index;
u2 index;
}local_variable_type_table[local_variable_type_table_length
];
}
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length;
}
RuntimeVisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
RuntimeInvisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
RuntimeVisibleParameterAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 num_parameters;
{ u2 num_annotations;
annotation annotations[num_annotations];
} parameter_annotations[num_parameters];
}
RuntimeInvisibleParameterAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u1 num_parameters;
{ u2 num_annotations;
annotation annotations[num_annotations];
} parameter_annotations[num_parameters];
}
AnnotationDefault_attribute {
u2 attribute_name_index;
u4 attribute_length;
element_value default_value;
}
BootstrapMethods_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_bootstrap_methods;
{ u2 bootstrap_method_ref;
u2 num_bootstrap_arguments;
u2 bootstrap_arguments[num_bootstrap_arguments];
} bootstrap_methods[num_bootstrap_methods];
}
import java.lang.Math;
public class Test {
private static final boolean DEBUG = true;
public static void main(String args[]) {
System.out.println("[101,200] pp count = " + Test.getCount(101, 200));
}
public static int getCount(int start, int end) {
int count = 0;
int index = start;
final int last = end;
if (index > last) {
return 0;
}
while (index < last + 1) {
final int key = (int)Math.sqrt((double)index);
int p = 2;
while (p < key + 1) {
if ((index % p) != 0) {
p ++;
continue;
} else {
break;
}
}
if (p == key + 1) {
count ++;
if (DEBUG) {
System.out.println(index);
}
}
index ++;
}
return count;
}
}
javap -verbose Test
Classfile Test.class
Last modified Jun 7, 2020; size 1001 bytes
MD5 checksum fcb73d6bf2253e087ca9e0cd30359cff
Compiled from "Test.java"
public class Test
SourceFile: "Test.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #14.#30 // java/lang/Object."<init>":()V
#2 = Fieldref #31.#32 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Class #33 // java/lang/StringBuilder
#4 = Methodref #3.#30 // java/lang/StringBuilder."<init>":()V
#5 = String #34 // [101,200] pp count =
#6 = Methodref #3.#35 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#7 = Methodref #13.#36 // Test.getCount:(II)I
#8 = Methodref #3.#37 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#9 = Methodref #3.#38 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#10 = Methodref #39.#40 // java/io/PrintStream.println:(Ljava/lang/String;)V
#11 = Methodref #41.#42 // java/lang/Math.sqrt:(D)D
#12 = Methodref #39.#43 // java/io/PrintStream.println:(I)V
#13 = Class #44 // Test
#14 = Class #45 // java/lang/Object
#15 = Utf8 DEBUG
#16 = Utf8 Z
#17 = Utf8 ConstantValue
#18 = Integer 1
#19 = Utf8 <init>
#20 = Utf8 ()V
#21 = Utf8 Code
#22 = Utf8 LineNumberTable
#23 = Utf8 main
#24 = Utf8 ([Ljava/lang/String;)V
#25 = Utf8 getCount
#26 = Utf8 (II)I
#27 = Utf8 StackMapTable
#28 = Utf8 SourceFile
#29 = Utf8 Test.java
#30 = NameAndType #19:#20 // "<init>":()V
#31 = Class #46 // java/lang/System
#32 = NameAndType #47:#48 // out:Ljava/io/PrintStream;
#33 = Utf8 java/lang/StringBuilder
#34 = Utf8 [101,200] pp count =
#35 = NameAndType #49:#50 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#36 = NameAndType #25:#26 // getCount:(II)I
#37 = NameAndType #49:#51 // append:(I)Ljava/lang/StringBuilder;
#38 = NameAndType #52:#53 // toString:()Ljava/lang/String;
#39 = Class #54 // java/io/PrintStream
#40 = NameAndType #55:#56 // println:(Ljava/lang/String;)V
#41 = Class #57 // java/lang/Math
#42 = NameAndType #58:#59 // sqrt:(D)D
#43 = NameAndType #55:#60 // println:(I)V
#44 = Utf8 Test
#45 = Utf8 java/lang/Object
#46 = Utf8 java/lang/System
#47 = Utf8 out
#48 = Utf8 Ljava/io/PrintStream;
#49 = Utf8 append
#50 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#51 = Utf8 (I)Ljava/lang/StringBuilder;
#52 = Utf8 toString
#53 = Utf8 ()Ljava/lang/String;
#54 = Utf8 java/io/PrintStream
#55 = Utf8 println
#56 = Utf8 (Ljava/lang/String;)V
#57 = Utf8 java/lang/Math
#58 = Utf8 sqrt
#59 = Utf8 (D)D
#60 = Utf8 (I)V
{
public Test();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String [101,200] pp count =
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: bipush 101
17: sipush 200
20: invokestatic #7 // Method getCount:(II)I
23: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
26: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
32: return
LineNumberTable:
line 8: 0
line 9: 32
public static int getCount(int, int);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=7, args_size=2
0: iconst_0
1: istore_2
2: iload_0
3: istore_3
4: iload_1
5: istore 4
7: iload_3
8: iload 4
10: if_icmple 15
13: iconst_0
14: ireturn
15: iload_3
16: iload 4
18: iconst_1
19: iadd
20: if_icmpge 81
23: iload_3
24: i2d
25: invokestatic #11 // Method java/lang/Math.sqrt:(D)D
28: d2i
29: istore 5
31: iconst_2
32: istore 6
34: iload 6
36: iload 5
38: iconst_1
39: iadd
40: if_icmpge 56
43: iload_3
44: iload 6
46: irem
47: ifeq 56
50: iinc 6, 1
53: goto 34
56: iload 6
58: iload 5
60: iconst_1
61: iadd
62: if_icmpne 75
65: iinc 2, 1
68: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
71: iload_3
72: invokevirtual #12 // Method java/io/PrintStream.println:(I)V
75: iinc 3, 1
78: goto 15
81: iload_2
82: ireturn
LineNumberTable:
line 12: 0
line 13: 2
line 14: 4
line 16: 7
line 17: 13
line 20: 15
line 21: 23
line 22: 31
line 23: 34
line 24: 43
line 25: 50
line 26: 53
line 31: 56
line 32: 65
line 34: 68
line 37: 75
line 38: 78
line 40: 81
StackMapTable: number_of_entries = 5
frame_type = 254 /* append */
offset_delta = 15
locals = [ int, int, int ]
frame_type = 253 /* append */
offset_delta = 18
locals = [ int, int ]
frame_type = 21 /* same */
frame_type = 18 /* same */
frame_type = 249 /* chop */
offset_delta = 5
}
00000000 ca fe ba be 00 00 00 33 00 3d 0a 00 0e 00 1e 09 |.......3.=......|
00000010 00 1f 00 20 07 00 21 0a 00 03 00 1e 08 00 22 0a |... ..!.......".|
00000020 00 03 00 23 0a 00 0d 00 24 0a 00 03 00 25 0a 00 |...#....$....%..|
00000030 03 00 26 0a 00 27 00 28 0a 00 29 00 2a 0a 00 27 |..&..'.(..).*..'|
00000040 00 2b 07 00 2c 07 00 2d 01 00 05 44 45 42 55 47 |.+..,..-...DEBUG|
00000050 01 00 01 5a 01 00 0d 43 6f 6e 73 74 61 6e 74 56 |...Z...ConstantV|
00000060 61 6c 75 65 03 00 00 00 01 01 00 06 3c 69 6e 69 |alue........<ini|
00000070 74 3e 01 00 03 28 29 56 01 00 04 43 6f 64 65 01 |t>...()V...Code.|
00000080 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c |..LineNumberTabl|
00000090 65 01 00 04 6d 61 69 6e 01 00 16 28 5b 4c 6a 61 |e...main...([Lja|
000000a0 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 |va/lang/String;)|
000000b0 56 01 00 08 67 65 74 43 6f 75 6e 74 01 00 05 28 |V...getCount...(|
000000c0 49 49 29 49 01 00 0d 53 74 61 63 6b 4d 61 70 54 |II)I...StackMapT|
000000d0 61 62 6c 65 01 00 0a 53 6f 75 72 63 65 46 69 6c |able...SourceFil|
000000e0 65 01 00 09 54 65 73 74 2e 6a 61 76 61 0c 00 13 |e...Test.java...|
000000f0 00 14 07 00 2e 0c 00 2f 00 30 01 00 17 6a 61 76 |......./.0...jav|
00000100 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 42 75 69 |a/lang/StringBui|
00000110 6c 64 65 72 01 00 15 5b 31 30 31 2c 32 30 30 5d |lder...[101,200]|
00000120 20 70 70 20 63 6f 75 6e 74 20 3d 20 0c 00 31 00 | pp count = ..1.|
00000130 32 0c 00 19 00 1a 0c 00 31 00 33 0c 00 34 00 35 |2.......1.3..4.5|
00000140 07 00 36 0c 00 37 00 38 07 00 39 0c 00 3a 00 3b |..6..7.8..9..:.;|
00000150 0c 00 37 00 3c 01 00 04 54 65 73 74 01 00 10 6a |..7.<...Test...j|
00000160 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 |ava/lang/Object.|
00000170 00 10 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 |..java/lang/Syst|
00000180 65 6d 01 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 |em...out...Ljava|
00000190 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b |/io/PrintStream;|
000001a0 01 00 06 61 70 70 65 6e 64 01 00 2d 28 4c 6a 61 |...append..-(Lja|
000001b0 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 |va/lang/String;)|
000001c0 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e |Ljava/lang/Strin|
000001d0 67 42 75 69 6c 64 65 72 3b 01 00 1c 28 49 29 4c |gBuilder;...(I)L|
000001e0 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 |java/lang/String|
000001f0 42 75 69 6c 64 65 72 3b 01 00 08 74 6f 53 74 72 |Builder;...toStr|
00000200 69 6e 67 01 00 14 28 29 4c 6a 61 76 61 2f 6c 61 |ing...()Ljava/la|
00000210 6e 67 2f 53 74 72 69 6e 67 3b 01 00 13 6a 61 76 |ng/String;...jav|
00000220 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 65 61 6d |a/io/PrintStream|
00000230 01 00 07 70 72 69 6e 74 6c 6e 01 00 15 28 4c 6a |...println...(Lj|
00000240 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b |ava/lang/String;|
00000250 29 56 01 00 0e 6a 61 76 61 2f 6c 61 6e 67 2f 4d |)V...java/lang/M|
00000260 61 74 68 01 00 04 73 71 72 74 01 00 04 28 44 29 |ath...sqrt...(D)|
00000270 44 01 00 04 28 49 29 56 00 21 00 0d 00 0e 00 00 |D...(I)V.!......|
00000280 00 01 00 1a 00 0f 00 10 00 01 00 11 00 00 00 02 |................|
00000290 00 12 00 03 00 01 00 13 00 14 00 01 00 15 00 00 |................|
000002a0 00 1d 00 01 00 01 00 00 00 05 2a b7 00 01 b1 00 |..........*.....|
000002b0 00 00 01 00 16 00 00 00 06 00 01 00 00 00 03 00 |................|
000002c0 09 00 17 00 18 00 01 00 15 00 00 00 3d 00 04 00 |............=...|
000002d0 01 00 00 00 21 b2 00 02 bb 00 03 59 b7 00 04 12 |....!......Y....|
000002e0 05 b6 00 06 10 65 11 00 c8 b8 00 07 b6 00 08 b6 |.....e..........|
000002f0 00 09 b6 00 0a b1 00 00 00 01 00 16 00 00 00 0a |................|
00000300 00 02 00 00 00 08 00 20 00 09 00 09 00 19 00 1a |....... ........|
00000310 00 01 00 15 00 00 00 c7 00 03 00 07 00 00 00 53 |...............S|
00000320 03 3d 1a 3e 1b 36 04 1d 15 04 a4 00 05 03 ac 1d |.=.>.6..........|
00000330 15 04 04 60 a2 00 3d 1d 87 b8 00 0b 8e 36 05 05 |...`..=......6..|
00000340 36 06 15 06 15 05 04 60 a2 00 10 1d 15 06 70 99 |6......`......p.|
00000350 00 09 84 06 01 a7 ff ed 15 06 15 05 04 60 a0 00 |.............`..|
00000360 0d 84 02 01 b2 00 02 1d b6 00 0c 84 03 01 a7 ff |................|
00000370 c1 1c ac 00 00 00 02 00 16 00 00 00 4a 00 12 00 |............J...|
00000380 00 00 0c 00 02 00 0d 00 04 00 0e 00 07 00 10 00 |................|
00000390 0d 00 11 00 0f 00 14 00 17 00 15 00 1f 00 16 00 |................|
000003a0 22 00 17 00 2b 00 18 00 32 00 19 00 35 00 1a 00 |"...+...2...5...|
000003b0 38 00 1f 00 41 00 20 00 44 00 22 00 4b 00 25 00 |8...A. .D.".K.%.|
000003c0 4e 00 26 00 51 00 28 00 1b 00 00 00 12 00 05 fe |N.&.Q.(.........|
000003d0 00 0f 01 01 01 fd 00 12 01 01 15 12 f9 00 05 00 |................|
000003e0 01 00 1c 00 00 00 02 00 1d |.........|