编译期常量运行期常量

2018-06-01  本文已影响0人  rock_fish

所属文集:ClassLoader串烧


编译期常量

在编译阶段,常量就被放到使用这个常量的方法的所在的类的常量池中
调用类,并没有直接引用到定义常量的类,因此不会触发定义常量的类 的初始化。
因此两者没有了关联,删除定义常量的类的.class文件也不影响。
如:i'm strChild会被放到Test06的常量池中。

摘自https://www.cnblogs.com/grefr/p/6094871.html
以Java为例,static final int a = 1将是一个编译时常量,编译后的符号表中将找不到a,所有对a的引用都被替换成了1
对于这句话,要确认如何查看符号表,怎么识别变成了1

案例1:

public class Test06 {
    public static void main(String[] args) {
        System.out.println(MyChild.strChild);
        //只输出:i'm strChild
        //System.out.println(MyParent.strParent);
        //只输出:i'm parent
    }
}
class MyChild extends MyParent {
    public static final String strChild = "i'm strChild";
    static {
        System.out.println("this is MyChild static...");
    }
}
class MyParent {
    public static final String strParent ="i'm parent";
    static {
        System.out.println("this is MyParent static");
    }
}
image.png
ldc命令参考

四、ldc系列
该系列命令负责把数值常量或String常量值从常量池中推送至栈顶。该命令后面需要给一个表示常量在常量池中位置(编号)的参数,
哪些常量是放在常量池呢?比如:final static int id=32768;final static float double=6.5。
对于const系列命令和push系列命令操作范围之外的数值类型常量,都放在常量池中.
另外,所有不是通过new创建的String都是放在常量池中的。
指令码 助记符 说明
0x12 ldc 将int, float或String型常量值从常量池中推送至栈顶
0x13 ldc_w 将int, float或String型常量值从常量池中推送至栈顶(宽索引)
0x14 ldc2_w 将long或double型常量值从常量池中推送至栈顶(宽索引)


运行期常量

public class Test07 {
    public static void main(String[] args) {
        System.out.println(MyParent07.a);
        System.out.println(MyParent07.str);
        System.out.println(MyParent07.str);
    }
}
class MyParent07{
    public static final String str = UUID.randomUUID().toString();
    public static final int a = 10;
    static {
        System.out.println("MyParent07 static executed");
    }
}

查看输出

[Loaded sun.nio.cs.US_ASCII$Decoder from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
10//先输出了10,之后才加载了MyParent07这个类
[Loaded MyParent07 from file:/C:/Users/rock/IdeaProjects/jvm-learn-07/jvmlearn07/target/classes/]
[Loaded java.util.UUID from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
[Loaded java.util.UUID$Holder from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
...
n多类加载信息忽略
...
MyParent07 static executed//静态代码块执行,只有首次加载才执行初始化
19019819-1961-4e92-8816-8d2dab9df34c//输出结果
19019819-1961-4e92-8816-8d2dab9df34c//输出结果
[Loaded java.lang.Shutdown from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]
[Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar]

Process finished with exit code 0

MyParent07.str是运行期常量;
不在调用者所在类的常量池中;
System.out.println(MyParent07.str);这样的调用就是对MyParent07的主动调用,会引起类的初始化(初始化之前肯定要先加载);

上一篇下一篇

猜你喜欢

热点阅读