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的正确的值,果然,连虚拟机都是爱偷懒的!

原文地址:https://www.cnblogs.com/think-in-java/p/5190758.html