JVM之类加载器中篇
先看一段代码吧!
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
8
这两段代码的区别就在于 a的赋值过程。 6/3 对于编译阶段是可知,所以此时的a是一个常量,而 new Random().nextInt(100)是一个编译阶段不可知的值。
这个时候又要谈到一个上一篇中提到的概念,所有的JAVA虚拟机实现必须在每个类或接口被JAVA程序“首次主动使用”时才初始化他们。
确实a是属于首次主动使用的一种特殊的情况,之所以特殊,是因为a是静态变量,符合主动使用的情况,但是6/3的结果是编译可知的,并且a是final的,只能被初始化一次,换句话说a的值是编译可知的,这样即使是首次主动使用,也不会对类进行初始化,因为不需要初始化,程序就能得到a的正确的值,果然,连虚拟机都是爱偷懒的!