字节码解析
在java中创建三个类
分别为:
public class Emp {
// 被final修饰
public static final int age=30;
static {
System.out.println("emp....");
}
}
public class User {
public static int age=30;
static {
System.out.println("user....");
}
}
public class Test {
public static void main(String[] args) {
System.out.println(User.age);
System.out.println(Emp.age);
}
}
根据运行Test中的main方法的结果可以看到
user....
30
30
Emp中的age被final修饰后,没有打印静态代码块中的内容。
这是为什么呢?
反编译代码
通过javap命令来进行反编译代码
/ 进入idea中target中的class文件夹下,打开Termail控制台。
使用命令
javap -v User
javap -v emp
编译User.class源码后的结果
警告: 二进制文件User包含com.test.User
Classfile /Users/lida/private/project/qmtools/out/production/scala/com/test/User.class
Last modified 2024-4-24; size 499 bytes
MD5 checksum 1d09d609093679118c6e95baffbcedf3
Compiled from "User.java"
public class com.test.User
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#20 // java/lang/Object."<init>":()V
#2 = Fieldref #6.#21 // com/test/User.age:I
#3 = Fieldref #22.#23 // java/lang/System.out:Ljava/io/PrintStream;
#4 = String #24 // user....
#5 = Methodref #25.#26 // java/io/PrintStream.println:(Ljava/lang/String;)V
#6 = Class #27 // com/test/User
#7 = Class #28 // java/lang/Object
#8 = Utf8 age
#9 = Utf8 I
#10 = Utf8 <init>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Utf8 LineNumberTable
#14 = Utf8 LocalVariableTable
#15 = Utf8 this
#16 = Utf8 Lcom/test/User;
#17 = Utf8 <clinit>
#18 = Utf8 SourceFile
#19 = Utf8 User.java
#20 = NameAndType #10:#11 // "<init>":()V
#21 = NameAndType #8:#9 // age:I
#22 = Class #29 // java/lang/System
#23 = NameAndType #30:#31 // out:Ljava/io/PrintStream;
#24 = Utf8 user....
#25 = Class #32 // java/io/PrintStream
#26 = NameAndType #33:#34 // println:(Ljava/lang/String;)V
#27 = Utf8 com/test/User
#28 = Utf8 java/lang/Object
#29 = Utf8 java/lang/System
#30 = Utf8 out
#31 = Utf8 Ljava/io/PrintStream;
#32 = Utf8 java/io/PrintStream
#33 = Utf8 println
#34 = Utf8 (Ljava/lang/String;)V
{
public static int age;
descriptor: I
flags: ACC_PUBLIC, ACC_STATIC
public com.test.User();
descriptor: ()V
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 9: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/test/User;
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: bipush 30
2: putstatic #2 // Field age:I
5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
8: ldc #4 // String user....
10: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
13: return
LineNumberTable:
line 11: 0
line 14: 5
line 15: 13
}
SourceFile: "User.java"
这个里面可以清晰的看到,age是在静态代码块中进行复制的。
编译Emp.class源码后的结果
警告: 二进制文件Emp包含com.test.Emp
Classfile /Users/lida/private/project/qmtools/out/production/scala/com/test/Emp.class
Last modified 2024-4-24; size 505 bytes
MD5 checksum a790a625f63a08555848173ef4d808a6
Compiled from "Emp.java"
public class com.test.Emp
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#21 // java/lang/Object."<init>":()V
#2 = Fieldref #22.#23 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #24 // emp....
#4 = Methodref #25.#26 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #27 // com/test/Emp
#6 = Class #28 // java/lang/Object
#7 = Utf8 age
#8 = Utf8 I
#9 = Utf8 ConstantValue
#10 = Integer 30
#11 = Utf8 <init>
#12 = Utf8 ()V
#13 = Utf8 Code
#14 = Utf8 LineNumberTable
#15 = Utf8 LocalVariableTable
#16 = Utf8 this
#17 = Utf8 Lcom/test/Emp;
#18 = Utf8 <clinit>
#19 = Utf8 SourceFile
#20 = Utf8 Emp.java
#21 = NameAndType #11:#12 // "<init>":()V
#22 = Class #29 // java/lang/System
#23 = NameAndType #30:#31 // out:Ljava/io/PrintStream;
#24 = Utf8 emp....
#25 = Class #32 // java/io/PrintStream
#26 = NameAndType #33:#34 // println:(Ljava/lang/String;)V
#27 = Utf8 com/test/Emp
#28 = Utf8 java/lang/Object
#29 = Utf8 java/lang/System
#30 = Utf8 out
#31 = Utf8 Ljava/io/PrintStream;
#32 = Utf8 java/io/PrintStream
#33 = Utf8 println
#34 = Utf8 (Ljava/lang/String;)V
{
public static final int age;
descriptor: I
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: int 30
public com.test.Emp();
descriptor: ()V
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 9: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/test/Emp;
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String emp....
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 14: 0
line 15: 8
}
SourceFile: "Emp.java"
可以清楚的看到,这块是在静态代码块外面进行的赋值
编译Test.class源码后的结果
Classfile /Users/lida/private/project/qmtools/out/production/scala/com/test/Test.class
Last modified 2024-4-24; size 569 bytes
MD5 checksum 32ffb98839c3ba98020e9fcc8917f021
Compiled from "Test.java"
public class com.test.Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#21 // java/lang/Object."<init>":()V
#2 = Fieldref #22.#23 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Fieldref #24.#25 // com/test/User.age:I
#4 = Methodref #26.#27 // java/io/PrintStream.println:(I)V
#5 = Class #28 // com/test/Emp
#6 = Class #29 // com/test/Test
#7 = Class #30 // java/lang/Object
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 LocalVariableTable
#13 = Utf8 this
#14 = Utf8 Lcom/test/Test;
#15 = Utf8 main
#16 = Utf8 ([Ljava/lang/String;)V
#17 = Utf8 args
#18 = Utf8 [Ljava/lang/String;
#19 = Utf8 SourceFile
#20 = Utf8 Test.java
#21 = NameAndType #8:#9 // "<init>":()V
#22 = Class #31 // java/lang/System
#23 = NameAndType #32:#33 // out:Ljava/io/PrintStream;
#24 = Class #34 // com/test/User
#25 = NameAndType #35:#36 // age:I
#26 = Class #37 // java/io/PrintStream
#27 = NameAndType #38:#39 // println:(I)V
#28 = Utf8 com/test/Emp
#29 = Utf8 com/test/Test
#30 = Utf8 java/lang/Object
#31 = Utf8 java/lang/System
#32 = Utf8 out
#33 = Utf8 Ljava/io/PrintStream;
#34 = Utf8 com/test/User
#35 = Utf8 age
#36 = Utf8 I
#37 = Utf8 java/io/PrintStream
#38 = Utf8 println
#39 = Utf8 (I)V
{
public com.test.Test();
descriptor: ()V
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 9: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/test/Test;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3 // Field com/test/User.age:I
6: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
12: bipush 30
14: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
17: return
LineNumberTable:
line 11: 0
line 12: 9
line 13: 17
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 args [Ljava/lang/String;
}
SourceFile: "Test.java"
结论
从Test.class的代码中就可以看到,获取User中的age时,是获取的静态代码中的数据。但是Emp中的age是常量
本文来自博客园,作者:King-DA,转载请注明原文链接:https://www.cnblogs.com/qingmuchuanqi48/articles/18156608

浙公网安备 33010602011771号