先看一段代码吧!
package com.tfdd.test; /**
* @desc
* @author chenqm
* @date 2016年2月15日
*/
public class FinalTest { public static void main(String[] args) {
System.out.println(FinalTest0.a);
} }
class FinalTest0{
public static final int a = 6/3;
static{
System.out.println("FinalTest0 static block");
}
}
输出结果可知吗?
我第一次看到的时候很肯定的认为是
FinalTest0 static block
2
然并卵~正确的结果是:
2
我只能说心好累,好吧?再看一段代码:
package com.tfdd.test; import java.util.Random; /**
* @desc
* @author chenqm
* @date 2016年2月15日
*/
public class FinalTest { public static void main(String[] args) {
System.out.println(FinalTest0.a);
} }
class FinalTest0{
public static final int a = new Random().nextInt(100);
static{
System.out.println("FinalTest0 static block");
}
}
结果是:
FinalTest0 static block
这两段代码的区别就在于 a的赋值过程。 6/3 对于编译阶段是可知,所以此时的a是一个常量,而 new Random().nextInt(100)是一个编译阶段不可知的值。
这个时候又要谈到一个上一篇中提到的概念,所有的JAVA虚拟机实现必须在每个类或接口被JAVA程序“首次主动使用”时才初始化他们。
确实a是属于首次主动使用的一种特殊的情况,之所以特殊,是因为a是静态变量,符合主动使用的情况,但是6/3的结果是编译可知的,并且a是final的,只能被初始化一次,换句话说a的值是编译可知的,这样即使是首次主动使用,也不会对类进行初始化,因为不需要初始化,程序就能得到a的正确的值,果然,连虚拟机都是爱偷懒的!