Java中的静态块未执行

Sth*_*ita 86 java static access-modifiers

class Test{
    public static void main(String arg[]){    
        System.out.println("**MAIN METHOD");
        System.out.println(Mno.VAL);//SOP(9090);
        System.out.println(Mno.VAL+100);//SOP(9190);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道static在加载类时执行的块.但是在这种情况下,类中的实例变量Mnofinal因为static块没有执行.

为什么会这样?如果我删除它final,它会工作正常吗?

首先分配哪个内存,static final变量或static块?

如果由于final访问修饰符而没有加载类,那么变量如何获取内存?

Mar*_*nik 132

  1. static final int字段是一个编译时间常数和它的值被硬编码到而不到其原点的参考目标类;
  2. 因此,您的主类不会触发包含该字段的类的加载;
  3. 因此,不执行该类中的静态初始化程序.

具体细节,编译后的字节码对应于:

public static void main(String arg[]){    
    System.out.println("**MAIN METHOD");
    System.out.println(9090)
    System.out.println(9190)
}
Run Code Online (Sandbox Code Playgroud)

一旦删除final,它就不再是编译时常量,并且上述特殊行为不适用.在Mno像您期望的类加载和它的静态初始化执行.

  • 所有评估都在编译时进行,最终结果硬编码到引用变量的所有位置. (18认同)
  • @SumitDesai确切地说,这仅适用于原始值和字符串文字.有关详细信息,请阅读[Java语言规范中的相关章节](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28) (8认同)
  • Marko,Sumit的怀疑是正确的,如果不是原始的,它是一些对象,那么这种硬编码是不可能的.不是吗?那么,在这种情况下,是否会加载该类并执行静态块? (2认同)

ass*_*ias 8

未加载类的原因VALfinal AND是用常量表达式初始化(9090).如果且仅当满足这两个条件时,在编译时评估常量并在需要时"硬编码".

要防止在编译时计算表达式(并使JVM加载您的类),您可以:


Xol*_*lve 5

如果你看到生成的字节码使用javap -v Test.class,main()出现如下:

public static void main(java.lang.String[]) throws java.lang.Exception;
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String **MAIN METHOD
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        11: sipush        9090
        14: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        17: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        20: sipush        9190
        23: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        26: return        
Run Code Online (Sandbox Code Playgroud)

您可以在" 11: sipush 9090"中清楚地看到直接使用静态最终值,因为Mno.VAL是编译时常量.因此,不需要加载Mno类.因此,不执行Mno的静态块.

您可以通过手动加载Mno来执行静态块,如下所示:

class Test{
    public static void main(String arg[]) throws Exception {
        System.out.println("**MAIN METHOD");
        Class.forName("Mno");                 // Load Mno
        System.out.println(Mno.VAL);
        System.out.println(Mno.VAL+100);
    }

}

class Mno{
    final static int VAL=9090;
    static{
        System.out.println("**STATIC BLOCK OF Mno\t:"+VAL);
    }
}
Run Code Online (Sandbox Code Playgroud)