2013-09-24 42 views
32

谁能解释发生了什么?静态块没有被调用

public class MagicFinal { 

    public static void main(String[] args) { 
     System.out.println(A.s); 
    } 
} 

class A { 
    static { 
     System.out.println("class has been loaded"); 
    } 

    public static final String s = "final"; 

    public static final Integer i = 3; 


} 

控制台:

最终

它是什么?我不明白为什么这个类没有被加载,我知道类在第一次调用时总是加载。字段s在字符串池中,我看到最终修饰符是魔术。

如果我删除final修饰符(public static String s = "final")我会得到

控制台:

类已经加载

最终

注:我已经改变了场ipublic static final int i = 3;并在conso中显示乐。 我得到了一样的字符串情况。为什么?

回答

46

"final"字符串字面值并且因此是compile-time constant expression。用编译时常量表达式初始化的变量的值直接硬编码到引用它的类中,并且不会引用原始类。因此,始发类的初始化不会发生。

作为面点,请注意类装载和类初始化之间的区别:只有后者的出现恰恰是由JLS规定。类加载可以在任何时候发生。

+1

好的,非常感谢!怎么样int? public static final int i = 3; //不会写类已经加载 public static final Integer i = 3; //写入类已加载 – idmitriev

+4

请阅读我在答案中链接到的编译时常量表达式的定义。 'int'是一个原始值,'String'是引用类型值的唯一特例,它可以包含在常量表达式中,而'Integer'既不是。 –

+0

@marko - 你告诉我,A类没有被装入吗?或者它是懒惰初始化的情况? – TheLostMind

3

这是用Java语言规范{8.3.2.1类变量的初始化程序}编写的内容。这必须在这里回答你的问题

一个微妙之处在于,在运行时,静态变量是最终的, 与编译时间常数的值首先被初始化初始化。这也是 适用于接口中的这​​些字段(第9.3.1节)。这些变量是 将永远不会被视为具有其默认初始值(§4.12.5),即使通过迂回 程序的“常数”。有关更多讨论,请参阅第12.4.2节和第13.4.9节。

+0

似乎你指的是* Java语言规范,第三版*。 *Java®Language Specification Java SE 7 Edition *中没有这样的段落。 – johnchen902

+0

是的。那是对的。我正在研究旧版本,但该声明也适用于JLS 7。下面的行来自JLS7 在运行时,最终初始化静态字段并使用常量 表达式(第15.28)初始化静态字段(第12.4.2节)。这也适用于接口(§9.3.1)中的这些字段 。这些字段是“常量”,即使通过不正确的程序(第13.4.9节), 也不会被观察到它们具有其默认初始值(§4.12.5)。 –

相关问题