源代码示例
/**
* 欢迎
*/
public interface Greet {
/**
* Say Hello
*/
void sayHello();
}
/**
* Java Class 常量池测试
*/
public class ClassConstant implements Greet {
/** Int */
private static final int intConstant = 1;
/** Long */
private static final long longConstant = 10L;
/** Boolean */
private static final boolean boolConstant = true;
/** Float */
private static final float floatConstant = 1.0f;
/** Double */
private static final double doubleConstant = 1d;
/** byte */
private static final byte byteConstant = 'A';
/** String */
private String stringConstant = "StringTest";
@Override
public void sayHello() {
System.out.println("Hello World");
}
public static void main(String[] args) {
new Thread(() -> {
Greet greet = new ClassConstant();
greet.sayHello();
}).start();
}
}
javap -v
Classfile /Users/techflowing/IdeaProjects/Test/src/ClassConstant.class
Last modified 2020-12-26; size 1517 bytes
MD5 checksum 273e320f183bc21a85496b9cfc47354c
Compiled from "ClassConstant.java"
public class ClassConstant implements Greet
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #14.#48 // java/lang/Object."<init>":()V
#2 = String #49 // StringTest
#3 = Fieldref #11.#50 // ClassConstant.stringConstant:Ljava/lang/String;
#4 = Fieldref #51.#52 // java/lang/System.out:Ljava/io/PrintStream;
#5 = String #53 // Hello World
#6 = Methodref #54.#55 // java/io/PrintStream.println:(Ljava/lang/String;)V
#7 = Class #56 // java/lang/Thread
#8 = InvokeDynamic #0:#61 // #0:run:()Ljava/lang/Runnable;
#9 = Methodref #7.#62 // java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
#10 = Methodref #7.#63 // java/lang/Thread.start:()V
#11 = Class #64 // ClassConstant
#12 = Methodref #11.#48 // ClassConstant."<init>":()V
#13 = InterfaceMethodref #15.#65 // Greet.sayHello:()V
#14 = Class #66 // java/lang/Object
#15 = Class #67 // Greet
#16 = Utf8 intConstant
#17 = Utf8 I
#18 = Utf8 ConstantValue
#19 = Integer 1
#20 = Utf8 longConstant
#21 = Utf8 J
#22 = Long 10l
#24 = Utf8 boolConstant
#25 = Utf8 Z
#26 = Utf8 floatConstant
#27 = Utf8 F
#28 = Float 1.0f
#29 = Utf8 doubleConstant
#30 = Utf8 D
#31 = Double 1.0d
#33 = Utf8 byteConstant
#34 = Utf8 B
#35 = Integer 65
#36 = Utf8 stringConstant
#37 = Utf8 Ljava/lang/String;
#38 = Utf8 <init>
#39 = Utf8 ()V
#40 = Utf8 Code
#41 = Utf8 LineNumberTable
#42 = Utf8 sayHello
#43 = Utf8 main
#44 = Utf8 ([Ljava/lang/String;)V
#45 = Utf8 lambda$main$0
#46 = Utf8 SourceFile
#47 = Utf8 ClassConstant.java
#48 = NameAndType #38:#39 // "<init>":()V
#49 = Utf8 StringTest
#50 = NameAndType #36:#37 // stringConstant:Ljava/lang/String;
#51 = Class #68 // java/lang/System
#52 = NameAndType #69:#70 // out:Ljava/io/PrintStream;
#53 = Utf8 Hello World
#54 = Class #71 // java/io/PrintStream
#55 = NameAndType #72:#73 // println:(Ljava/lang/String;)V
#56 = Utf8 java/lang/Thread
#57 = Utf8 BootstrapMethods
#58 = MethodHandle #6:#74 // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#59 = MethodType #39 // ()V
#60 = MethodHandle #6:#75 // invokestatic ClassConstant.lambda$main$0:()V
#61 = NameAndType #76:#77 // run:()Ljava/lang/Runnable;
#62 = NameAndType #38:#78 // "<init>":(Ljava/lang/Runnable;)V
#63 = NameAndType #79:#39 // start:()V
#64 = Utf8 ClassConstant
#65 = NameAndType #42:#39 // sayHello:()V
#66 = Utf8 java/lang/Object
#67 = Utf8 Greet
#68 = Utf8 java/lang/System
#69 = Utf8 out
#70 = Utf8 Ljava/io/PrintStream;
#71 = Utf8 java/io/PrintStream
#72 = Utf8 println
#73 = Utf8 (Ljava/lang/String;)V
#74 = Methodref #80.#81 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#75 = Methodref #11.#82 // ClassConstant.lambda$main$0:()V
#76 = Utf8 run
#77 = Utf8 ()Ljava/lang/Runnable;
#78 = Utf8 (Ljava/lang/Runnable;)V
#79 = Utf8 start
#80 = Class #83 // java/lang/invoke/LambdaMetafactory
#81 = NameAndType #84:#88 // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#82 = NameAndType #45:#39 // lambda$main$0:()V
#83 = Utf8 java/lang/invoke/LambdaMetafactory
#84 = Utf8 metafactory
#85 = Class #90 // java/lang/invoke/MethodHandles$Lookup
#86 = Utf8 Lookup
#87 = Utf8 InnerClasses
#88 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
#89 = Class #91 // java/lang/invoke/MethodHandles
#90 = Utf8 java/lang/invoke/MethodHandles$Lookup
#91 = Utf8 java/lang/invoke/MethodHandles
{
public ClassConstant();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String StringTest
7: putfield #3 // Field stringConstant:Ljava/lang/String;
10: return
LineNumberTable:
line 4: 0
line 18: 4
public void sayHello();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #5 // String Hello World
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 22: 0
line 23: 8
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
0: new #7 // class java/lang/Thread
3: dup
4: invokedynamic #8, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
9: invokespecial #9 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
12: invokevirtual #10 // Method java/lang/Thread.start:()V
15: return
LineNumberTable:
line 26: 0
line 29: 12
line 30: 15
}
SourceFile: "ClassConstant.java"
InnerClasses:
public static final #86= #85 of #89; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
0: #58 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
#59 ()V
#60 invokestatic ClassConstant.lambda$main$0:()V
#59 ()V
16进制数据
CAFE BABE 0000 0034 005C 0A00 0E00 3008 0031 0900 0B00 3209 0033 0034 0800 350A 0036 0037 0700 3812 0000 003D 0A00 0700 3E0A
0007 003F 0700 400A 000B 0030 0B00 0F00 4107 0042 0700 4301 000B 696E 7443 6F6E 7374 616E 7401 0001 4901 000D 436F 6E73 7461
6E74 5661 6C75 6503 0000 0001 0100 0C6C 6F6E 6743 6F6E 7374 616E 7401 0001 4A05 0000 0000 0000 000A 0100 0C62 6F6F 6C43 6F6E
7374 616E 7401 0001 5A01 000D 666C 6F61 7443 6F6E 7374 616E 7401 0001 4604 3F80 0000 0100 0E64 6F75 626C 6543 6F6E 7374 616E
7401 0001 4406 3FF0 0000 0000 0000 0100 0C62 7974 6543 6F6E 7374 616E 7401 0001 4203 0000 0041 0100 0E73 7472 696E 6743 6F6E
7374 616E 7401 0012 4C6A 6176 612F 6C61 6E67 2F53 7472 696E 673B 0100 063C 696E 6974 3E01 0003 2829 5601 0004 436F 6465 0100
0F4C 696E 654E 756D 6265 7254 6162 6C65 0100 0873 6179 4865 6C6C 6F01 0004 6D61 696E 0100 1628 5B4C 6A61 7661 2F6C 616E 672F
5374 7269 6E67 3B29 5601 000D 6C61 6D62 6461 246D 6169 6E24 3001 000A 536F 7572 6365 4669 6C65 0100 1243 6C61 7373 436F 6E73
7461 6E74 2E6A 6176 610C 0026 0027 0100 0A53 7472 696E 6754 6573 740C 0024 0025 0700 440C 0045 0046 0100 0B48 656C 6C6F 2057
6F72 6C64 0700 470C 0048 0049 0100 106A 6176 612F 6C61 6E67 2F54 6872 6561 6401 0010 426F 6F74 7374 7261 704D 6574 686F 6473
0F06 004A 1000 270F 0600 4B0C 004C 004D 0C00 2600 4E0C 004F 0027 0100 0D43 6C61 7373 436F 6E73 7461 6E74 0C00 2A00 2701 0010
6A61 7661 2F6C 616E 672F 4F62 6A65 6374 0100 0547 7265 6574 0100 106A 6176 612F 6C61 6E67 2F53 7973 7465 6D01 0003 6F75 7401
0015 4C6A 6176 612F 696F 2F50 7269 6E74 5374 7265 616D 3B01 0013 6A61 7661 2F69 6F2F 5072 696E 7453 7472 6561 6D01 0007 7072
696E 746C 6E01 0015 284C 6A61 7661 2F6C 616E 672F 5374 7269 6E67 3B29 560A 0050 0051 0A00 0B00 5201 0003 7275 6E01 0016 2829
4C6A 6176 612F 6C61 6E67 2F52 756E 6E61 626C 653B 0100 1728 4C6A 6176 612F 6C61 6E67 2F52 756E 6E61 626C 653B 2956 0100 0573
7461 7274 0700 530C 0054 0058 0C00 2D00 2701 0022 6A61 7661 2F6C 616E 672F 696E 766F 6B65 2F4C 616D 6264 614D 6574 6166 6163
746F 7279 0100 0B6D 6574 6166 6163 746F 7279 0700 5A01 0006 4C6F 6F6B 7570 0100 0C49 6E6E 6572 436C 6173 7365 7301 00CC 284C
6A61 7661 2F6C 616E 672F 696E 766F 6B65 2F4D 6574 686F 6448 616E 646C 6573 244C 6F6F 6B75 703B 4C6A 6176 612F 6C61 6E67 2F53
7472 696E 673B 4C6A 6176 612F 6C61 6E67 2F69 6E76 6F6B 652F 4D65 7468 6F64 5479 7065 3B4C 6A61 7661 2F6C 616E 672F 696E 766F
6B65 2F4D 6574 686F 6454 7970 653B 4C6A 6176 612F 6C61 6E67 2F69 6E76 6F6B 652F 4D65 7468 6F64 4861 6E64 6C65 3B4C 6A61 7661
2F6C 616E 672F 696E 766F 6B65 2F4D 6574 686F 6454 7970 653B 294C 6A61 7661 2F6C 616E 672F 696E 766F 6B65 2F43 616C 6C53 6974
653B 0700 5B01 0025 6A61 7661 2F6C 616E 672F 696E 766F 6B65 2F4D 6574 686F 6448 616E 646C 6573 244C 6F6F 6B75 7001 001E 6A61
7661 2F6C 616E 672F 696E 766F 6B65 2F4D 6574 686F 6448 616E 646C 6573 0021 000B 000E 0001 000F 0007 001A 0010 0011 0001 0012
0000 0002 0013 001A 0014 0015 0001 0012 0000 0002 0016 001A 0018 0019 0001 0012 0000 0002 0013 001A 001A 001B 0001 0012 0000
0002 001C 001A 001D 001E 0001 0012 0000 0002 001F 001A 0021 0022 0001 0012 0000 0002 0023 0002 0024 0025 0000 0004 0001 0026
0027 0001 0028 0000 0027 0002 0001 0000 000B 2AB7 0001 2A12 02B5 0003 B100 0000 0100 2900 0000 0A00 0200 0000 0400 0400 1200
0100 2A00 2700 0100 2800 0000 2500 0200 0100 0000 09B2 0004 1205 B600 06B1 0000 0001 0029 0000 000A 0002 0000 0015 0008 0016
0009 002B 002C 0001 0028 0000 0030 0003 0001 0000 0010 BB00 0759 BA00 0800 00B7 0009 B600 0AB1 0000 0001 0029 0000 000E 0003
0000 0018 000C 001B 000F 001C 100A 002D 0027 0001 0028 0000 002F 0002 0001 0000 000F BB00 0B59 B700 0C4B 2AB9 000D 0100 B100
0000 0100 2900 0000 0E00 0300 0000 1900 0800 1A00 0E00 1B00 0300 2E00 0000 0200 2F00 5700 0000 0A00 0100 5500 5900 5600 1900
3900 0000 0C00 0100 3A00 0300 3B00 3C00 3B
常量池类型分析
Integer & Float
CONSTANT_Integer_info和CONSTANT_Float_info这两种结构分别用来表示int和float类型的常量,两者的结构很类似,都用4个字节来表示具体的数值常量,它们的结构定义如下所示
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
以 #19
为例
#19 = Integer 1
对应的数据为
0300 0000 01
- 03 表示:CONSTANT_Integer_info
- 00 0000 01,表示数字 1
Long & Double
CONSTANT_Long_info和CONSTANT_Double_info这两种结构分别用来表示long和double类型的常量,二者都用8个字节表示具体的常量数值,它们的结构如下面的代码所示
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
以 #22
为例
#22 = Long 10l
对应的数据为
0500 0000 0000 0000 0A
- 05 表示:CONSTANT_Long_info
- 高4位:00 0000 00
- 低4位:00 0000 0A,表示 10
Utf8
CONSTANT_Utf8_info存储了字符串的内容,结构如下所示
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
它由三部分构成:第一个字节是tag,值为固定值1;tag之后的两个字节length并不是表示字符串有多少个字符,而是表示第三部分byte数组的长度;第三部分是采用MUTF-8编码的长度为length的字节数组.
以 #53
为例
#53 = Utf8 Hello World
对应的数据为
0100 0B48 656C 6C6F 2057 6F72 6C64
- 01 表示:CONSTANT_Utf8_info
- 00 0B表示:表示bytes长度 11
- 48 656C 6C6F 2057 6F72 6C64 表示:hello World,其中48的10进制为 72,表示字母 H
String
CONSTANT_String_info用来表示java.lang.String类型的常量对象。它与CONSTANT_Utf8_info的区别是CONSTANT_Utf8_info存储了字符串真正的内容,而CONSTANT_String_info并不包含字符串的内容,仅仅包含一个指向常量池中CONSTANT_Utf8_info常量类型的索引。第一部分是tag,值为固定 8,string_index 是一个常量池索引,指向 CONSTANT_Utf8_info 常量,结构如下所示
CONSTANT_String_info {
u1 tag;
u2 string_index; // CONSTANT_Utf8_info
}
以 #5
为例
#5 = String #53 // Hello World
对应的数据为
0800 35
- 08 表示:CONSTANT_String_info
- 00 35 表示 string_index,十进制数据 53 指向常量池 53
#53 = Utf8 Hello World
Class
CONSTANT_Class_info 结构表示类和接口,结构与 CONSTANT_String_info 非常类似
CONSTANT_Class_info {
u1 tag;
u2 name_index; //CONSTANT_Utf8_info
}
以 #7
为例
#7 = Class #56 // java/lang/Thread
对应的数据为
07 0038
- 07 表示:CONSTANT_Class_info
- 0038 表示 string_index,十进制数据 56 指向常量池 56
#56 = Utf8 java/lang/Thread
NameAndType
CONSTANT_NameAndType_info 结构用来表示字段或者方法
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index; //CONSTANT_Utf8_info
u2 descriptor_index; //CONSTANT_Utf8_info
}
以 #48
为例
#48 = NameAndType #38:#39 // "<init>":()V
对应的数据为
0C00 2600 27
- name_index 数据为 0026,10进制为 38
- descriptor_index 数据为 0027,10进制数据为39
#38 = Utf8 <init>
#39 = Utf8 ()V
Fieldref、Methodref、InterfaceMethodref
这三种类型结构类似
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index; //CONSTANT_NameAndType_info
}
以 #3
为例
#3 = Fieldref #11.#50 // ClassConstant.stringConstant:Ljava/lang/String;
对应的数据为
0900 0B00 32
- 09 表示tag,是CONSTANT_Fieldref_info
- 00 0B class_index 指向 #11
- 00 32 name_and_type_index 指向 #50
#11 = Class #64 // ClassConstant
#50 = NameAndType #36:#37 // stringConstant:Ljava/lang/String;
其余两种类似,不做分析。
从JDK 1.7 开始,为了更好地支持动态语言调用,新增了3种常量池类型 CONSTANT_MethodType_info、CONSTANT_MethodHandle_info、CONSTANT_InvokeDynamic_info
MethodType
CONSTANT_MethodType_info 结构用于表示方法类型
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index; //CONSTANT_Utf8_info
}
以 #59
为例
#59 = MethodType #39 // ()V
响应数据为
1000 27
- 10 表示tag,值为16
- 00 27 表示descriptor_index,值为39,指向
#39 = Utf8 ()V
MethodHandler
CONSTANT_MethodHandle_info 表示方法句柄,结构为
CONSTANT_MethodHandle_info {
u1 tag; //15
u1 reference_kind; //1~9
u2 reference_index; //取决于kind
}
- tag 定值为15
- reference_kind 项的值必须在范围 1~9,它表示方法句柄的类型,方法句柄类型决定句柄的字节码行为
- reference_index 的值必须是对常量池表的有效索引
reference_index 格式:
kind | 说明 | index | 版本 |
---|---|---|---|
1 | REF_getField | CONSTANT_Fieldref_info | |
2 | REF_getStatic | CONSTANT_Fieldref_info | |
3 | REF_putField | CONSTANT_Fieldref_info | |
4 | REF_putStatic | CONSTANT_Fieldref_info | |
5 | REF_invokeVirtual | CONSTANT_Methodref_info | |
8 | REF_newInvokeSpecial | CONSTANT_Methodref_info | |
6 | REF_invokeStatic | CONSTANT_Methodref_info | 52.0- |
6 | REF_invokeStatic | CONSTANT_Methodref_info / CONSTANT_InterfaceMethodref_info | 52.0+ |
7 | REF_invokeSpecial | CONSTANT_Methodref_info / CONSTANT_InterfaceMethodref_info | 52.0- |
7 | REF_invokeSpecial | CONSTANT_Methodref_info / CONSTANT_InterfaceMethodref_info | 52.0+ |
9 | REF_invokeInterface | CONSTANT_InterfaceMethodref_info |
以 #58
为例
#58 = MethodHandle #6:#74 // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
相应数据为:
0F06 004A
- reference_kind 值为 6,类型是 REF_invokeStatic,指向类型为 CONSTANT_Methodref_info
- 004A 值为 74,指向 #74 数据
#74 = Methodref #80.#81 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
InvokeDynamic
CONSTANT_InvokeDynamic_info 的主要作用是为 invokedynamic 指令提供的启动引导方法
CONSTANT_InvokeDynamic_info {
u1 tag; //18
u2 bootstrap_method_attr_index; //index into the bootstrap_methods array of the bootstrap method table
u2 name_and_type_index; //CONSTANT_NameAndType_info
}
- tag 为定值 18 ,表示 CONSTANT_InvokeDynamic_info
- bootstrap_method_attr_index 项的值必须是对当前 Class 文件中引导方法表的 bootstrap_methods 数组的有效索引
- name_and_type_index 的值是对常量池的表的有效索引,类型必须是 CONSTANT_NameAndType_info 类型,表示方法名和方法描述符
以 #8
为例
#8 = InvokeDynamic #0:#61 // #0:run:()Ljava/lang/Runnable;
相应数据为
12 0000 003D
- bootstrap_method_attr_index 值为 0
- 003D 值为 61,指向常量池索引
#61
#61 = NameAndType #76:#77 // run:()Ljava/lang/Runnable;