JVM学习第三天-常量本质含义与反编译及助记符含义
根据昨天的代码:
public class MyTest1 {
public static void main(String[] args) {
System.err.println(MyChild1.str2);
}
}
class MyParent1{
public static String str="hello world";
static {
System.err.println("MyParent1 static block");
}
}
class MyChild1 extends MyParent1{
public static String str2="welcome";
static {
System.err.println("MyChild1 static block");
}
}
这段代码的运行结果:
这个结果表名我们的父类初始化了,我们的子类没有被初始化但是我们子类没有被初始化我们的子类已经被加载进去了。
可以通过JVM命令:
- -XX:+TraceClassLoading ,用于追踪类的加载信息并打印出来
- -XX:+ 表示开启option选项
- -XX:- 表示关闭option选项
- -XX:= 表示option选项这是为value
再次运行代码结果:
这里显示MyParent1和MyChild1已经被加载了
事列2代码:
public class MyTest2 {
public static void main(String[] args) {
System.err.println(MyPreant2.str);
}
}
class MyPreant2{
public static final String str ="hello world";
static {
System.err.println("MyParent2 static block");
}
}
运行结果:
那么这里没有静态代码块没有被打印出来的原因就是因为str这个静态常量所在的地方是在MyTest2这个常量池中,所以没有初始化。
小总结
/**
* 常量在编译阶段会存入到这个常量的方法所在类的常量池当中
* 本质上,调用类并没有直接引用到定义常量的类
* 因此并不会触发定义常量类的初始化
* 注意:这里指的是将常量存在Mytest2的常量池中,值周MyTst2与MyParent2没有任何关系
* 甚至,我们可以将MyParent2的class文件删除
*/
这个我是看别人这样实践过自己也实践过我们可以Myparent2编译好的文件给删掉。
反编译与助记符
$ javap -c MyTest2.class
运行结果:
请看倒数第三行:
String hello world对应的是MyPreant2.str那么这证明什么呢就是编译的时候MyPreant2.str就已经是hello world了所以这个常量就存储在MyTest2的常量池当中。
助记符了解
- idc表示将int,float或是String类型的常量值从常量吃对送至栈顶
- bipush表示将单字节(-128 ~127)的常量值推送至栈顶
- sipush表示将一个短整型常量值(-32768~32767)推送至栈顶
- iconst_1表示将int类型1推送至栈顶 (iconst_m1 ~ iconst_5)
- 访问类的静态变量:getstatic
- 对该静态变量赋值:putstatic
- 调用类的静态方法:invokestatic
总结:
/**
* 常量在编译阶段会存入到这个常量的方法所在类的常量池当中
* 本质上,调用类并没有直接引用到定义常量的类
* 因此并不会触发定义常量类的初始化
* 注意:这里指的是将常量存在Mytest2的常量池中,值周MyTst2与MyParent2没有任何关系
* 甚至,我们可以将MyParent2的class文件删除
*/
/**
* 助记符:
* idc表示将int,float或是String类型的常量值从常量吃对送至栈顶
* bipush表示将单字节(-128 ~127)的常量值推送至栈顶
* sipush表示将一个短整型常量值(-32768~32767)推送至栈顶
* iconst_1表示将int类型1推送至栈顶 (iconst_m1 ~ iconst_5)
*/
h表示将单字节(-128 ~127)的常量值推送至栈顶
- sipush表示将一个短整型常量值(-32768~32767)推送至栈顶
- iconst_1表示将int类型1推送至栈顶 (iconst_m1 ~ iconst_5)
*/