执行顺序,静态块

时间:2013-04-12 07:51:03

标签: java

我有以下情况     package com.example.test;

public class StaticTest {

    public static final String STATIC_VAR="Static Var";

    static{
        System.out.println("Static Block Called....");
    }
public static void init(){}
}

package com.example.test;

public class MainClass {
    public static void main(String[] args) {
        System.out.println("Test static initialization");
        String staticvar =StaticTest.STATIC_VAR;
        System.out.println("Referred static variable--> "+ staticvar);
        System.out.println("Calling static method");
        StaticTest.init();
        System.out.println("Static method invoked");
    }

}

我得到的输出是

Test static initialization
Referred static variable--> Static Var
Calling static method
**Static Block Called....**
Static method invoked

我期待的输出是

Test static initialization
**Static Block Called....**
Referred static variable--> Static Var
Calling static method
Static method invoked

我在想,只要我引用静态变量,静态块就会被执行。

任何解释?

3 个答案:

答案 0 :(得分:3)

String staticvar =StaticTest.STATIC_VAR; 

不加载课程StaticTest。相反,编译器将常量的内联到MainClass。所以在运行时,这段代码将被执行:

String staticvar = "Static Var"; 

JLS称之为“constant”:

  

基本类型或类型String的变量,即final和   用编译时常量表达式(第15.28节)初始化,是   称为常数变量。

这意味着StaticTest.init();是VM第一次必须实际加载类。这导致执行静态块。

答案 1 :(得分:3)

因为变量是public static final,所以它由编译器内联。

对它的所有引用都被实际值替换,因为它不能改变,这称为编译时间常量。

您的代码基本上被编译为:

System.out.println("Test static initialization");
String staticvar = "Static Var";

如果将值赋给方法的返回值 -

public static final String STATIC_VAR=getStaticVar();
private static String getStaticVar() {
    return "Static Var";
}

您将获得您期望的结果。

有一个good SO answer解释内联和JLS对编译时常量给出的保证。

答案 2 :(得分:0)

主要原因是您将STATIC_VAR声明为常量值,它将由编译器内联而不是被引用。将代码更改为

public static /*final*/ String STATIC_VAR="Static Var";

你会得到你期望的行为。

请参阅Java语言规范的§12.4.1. When Initialization Occurs

  

类或接口类型T将在第一次出现以下任何一个之前立即初始化:

     
      
  • ...
  •   
  •   使用T声明的静态字段,字段不是常量变量(§4.12.4)。
  •   

请参阅inlining关于技术背景的常量值的其他答案。