下面两段代码的输出:
// public class Test { public static void main(String[] args) { System.out.println(Test2.a); } } //字面量 public class Test2 { static { System.out.print("OK"); } public static final String a= "JD"; } //new对象 public class Test2 { static { System.out.print("OK"); } public static final String a= new String("JD"); }
字面量输出:JD
new对象输出:OKJD
为什么呢?他俩的区别就是,执行static块!!那么什么时候会执行 static 块呢?答案肯定是 类加载的时候。通过简单的结论:字面量当外部类,未加载类。
那么问题又来了,为什么未加载呢?这个时候,编译器常量 应该可以解除你的疑惑。只需要弄明白,什么是编译期常量!!!!
--------------------------------------
参考:https://www.cnblogs.com/Vdiao/p/6040125.html
http://www.cnblogs.com/ningvsban/p/3591610.html
看了上边两篇文章,你应该是,常量分为 编译期常量 和 运行时常量
编译期常量:它的值在编译期就可以确定的常量
例如:
public static final String a= "JD";
运行时常量:只有在运行时,通过加载类之后才能确定其值,值的初始化是在类加载的过程中。
例如:
public static final String a= new String("JD");
通过 new 对象,此时 a 存储的是 String 对应实例对象 的引用,只有在在运行的时候,才可以在加载类之后,通过初始化之后,才会在堆中创建对象,从而得到对象的引用,赋值给 a。
对于字面量的a,它在编译的时候,编译器就可以确定其值,并将其被引用的地方,等价替换。也就不需要后续的类的加载,也算是一种性能优化!
----------------------------------------------------------------
从另外一个角度看,咱们看反编译后,字节码文件里边的现象:
当引用字面量的常量字符串,这个时候,编译器在编译的时候,通过计算得出相同的值,等价替换。
当如果是new对象,这时候,对应的调用 Test2类中的 gestatic(),此时则需要加载 Test2 类。