美文网首页
编译期常量运行期常量

编译期常量运行期常量

作者: rock_fish | 来源:发表于2018-06-01 11:26 被阅读0次

    所属文集: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的主动调用,会引起类的初始化(初始化之前肯定要先加载);

    相关文章

      网友评论

          本文标题:编译期常量运行期常量

          本文链接:https://www.haomeiwen.com/subject/xocylftx.html