06_常量的本质含义与反编译及助记符详解
查看类加载
通过虚拟机的参数查看类是否被加载:
- -XX:+TraceClassLoading:用于追踪类的加载信息并打印出来。
-XX:+<options>
:表示开启options选项
-XX:-<options>
:表示关闭options选项
-XX:<options>=<value>
:表示将option选项的值设置为value
所有的JVM参数都是以**-XX:**开头,
代码:
public class MyTest1 {
public static void main(String[] args) {
System.out.println(MyChild1.str);
}
}
class MyParent1{
public static String str = "hello_world";
static{
System.out.println("MyParent1 static static block");
}
}
class MyChild1 extends MyParent1{
public static String str2 = "welcome";
static {
System.out.println("MyChild1 static block");
}
}
结果:
......
[Loaded top.tomxwd.classloader.MyTest1 from file:/E:/IDEA-workspace/jvm-test-01/target/classes/]
......
[Loaded top.tomxwd.classloader.MyParent1 from file:/E:/IDEA-workspace/jvm-test-01/target/classes/]
[Loaded top.tomxwd.classloader.MyChild1 from file:/E:/IDEA-workspace/jvm-test-01/target/classes/]
MyParent1 static static block
hello_world
......
说明虽然没有对MyChild1进行初始化,但是JVM也完成了对MyChild1的加载。
常量的本质含义
代码:
public class MyTest2 {
public static void main(String[] args) {
System.out.println(MyParent2.str);
}
}
class MyParent2{
public static final String str = "hello world";
static {
System.out.println("MyParent2 static block");
}
}
输出:
hello world
发现static代码块并不会被执行。
因为final是个常量,也就是说str被赋值之后就不会被改变,所以在**编译阶段,这个常量就会被存入到调用这个常量的方法的所在的类的常量池当中,本质上,调用类并没有直接引用到定义常量的类,因此,并不会触发定义常量的类的初始化。**所以上述代码,不会初始化MyParent2,尽管main方法调用了MyParent2的str。
注意:这里指的是将常量存放到了MyTest2的常量池中,之后MyTest2与MyParent2就没有任何关系了,甚至我们可以将MyParent2的class文件删除。
反编译以及助记符详解
在终端进行反编译,结果:
E:\IDEA-workspace\jvm-test-01\target\classes>javap -c top.tomxwd.classloader.MyTest2
Compiled from "MyTest2.java"
public class top.tomxwd.classloader.MyTest2 {
public top.tomxwd.classloader.MyTest2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String hello world
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
可以看到,MyParent2.str已经在编译期就变成了hello world;
助记符:
- ldc:表示将int,float或者String类型的常量值从常量池推送至栈顶。
- bipush:表示将单字节(-128~127)的常量值推送至栈顶。
- sipush:表示将短整型(-32768~32767)的常量值推送至栈顶。
- iconst_m1~iconst5:表示将int类型的-1~5推送至栈顶。
代码:
public class MyTest2 {
public static void main(String[] args) {
System.out.println(MyParent2.str);
System.out.println(MyParent2.s);
System.out.println(MyParent2.i);
System.out.println(MyParent2.m);
}
}
class MyParent2{
public static final String str = "hello world";
public static final short s = 7;
public static final int i = 128;
public static final int m = 1;
static {
System.out.println("MyParent2 static block");
}
}
反编译:
E:\IDEA-workspace\jvm-test-01\target\classes>javap -c top.tomxwd.classloader.MyTest2
Compiled from "MyTest2.java"
public class top.tomxwd.classloader.MyTest2 {
public top.tomxwd.classloader.MyTest2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String hello world
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: bipush 7
13: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
16: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
19: sipush 128
22: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
25: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
28: iconst_1
29: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
32: return
}
评论区