Java 中的静态块未执行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16853747/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:10:45  来源:igfitidea点击:

Static block in Java not executed

javastaticaccess-modifiers

提问by Sthita

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);
    }
}

I know that a staticblock executed when class loaded. But in this case the instance variable inside class Mnois final, because of that the staticblock is not executing.

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

Why is that so? And if I would remove the final, would it work fine?

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

Which memory will be allocated first, the static finalvariable or the staticblock?

哪个内存将首先分配,static final变量还是static块?

If due to the finalaccess modifier the class does not get loaded, then how can the variable get memory?

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

回答by Marko Topolnik

  1. A static final intfield is a compile-time constantand its value is hardcoded into the destination class without a reference to its origin;
  2. therefore your main class does not trigger the loading of the class containing the field;
  3. therefore the static initializer in that class is not executed.
  1. 一个static final int字段是一个编译时常量,它的值被硬编码到目标类中,没有对其来源的引用;
  2. 因此您的主类不会触发包含该字段的类的加载;
  3. 因此不执行该类中的静态初始值设定项。

In specific detail, the compiled bytecode corresponds to this:

具体来说,编译后的字节码对应如下:

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

As soon as you remove final, it is no longer a compile-time constant and the special behavior described above does not apply. The Mnoclass is loaded as you expect and its static initializer executes.

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

回答by assylias

The reason why the class is not loaded is that VALis finalANDit is initialised with a constant expression(9090). If, and only if, those two conditions are met, the constant is evaluated at compile time and "hardcoded" where needed.

为什么没有加载类的原因是,VALfinal它被初始化与常量表达式(9090)。当且仅当满足这两个条件时,才会在编译时评估常量并在需要时进行“硬编码”。

To prevent the expression from being evaluated at compile time (and to make the JVM load your class), you can either:

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

  • remove the final keyword:

    static int VAL = 9090; //not a constant variable any more
    
  • or change the right hand side expression to something non constant (even if the variable is still final):

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    
  • 删除 final 关键字:

    static int VAL = 9090; //not a constant variable any more
    
  • 或将右侧表达式更改为非常量(即使变量仍然是最终的):

    final static int VAL = getInt(); //not a constant expression any more
    static int getInt() { return 9090; }
    

回答by Xolve

If you see generated bytecode using javap -v Test.class, main() comes out like:

如果您看到使用 生成的字节码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        

You can clearly see in "11: sipush 9090" that static final value is directly used, because Mno.VAL is a compile time constant. Therefore it is not required to load Mno class. Hence static block of Mno is not executed.

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

You can execute the static block by manually loading Mno as below:

您可以通过手动加载 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);
    }
}

回答by Ketan_Patel

1)Actually you have not extends that Mno class so when compilation start it will generate constant of variable VAL and when execution start when that variable is needed its load thats from memory.so its not required your class reference so that static bock is not executed.

1)实际上你还没有扩展那个 Mno 类,所以当编译开始时它会生成变量 VAL 的常量,当需要该变量时它从内存中加载它的执行开始时。所以它不需要你的类引用,所以不执行静态块.

2)if A class extend that Mno class at that time that static block is included in A class if you do this then that static block is executed. for example.. public class A extends Mno{

2)如果一个类在那个时候扩展了那个 Mno 类,那么静态块包含在 A 类中,如果你这样做,那么该静态块将被执行。例如..公共类 A 扩展了 Mno{

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);
    }
}

回答by Fabyen

As far as I know, it will be executed in order of appearance. For instance :

据我所知,它将按照出现的顺序执行。例如 :

 public class Statique {
     public static final String value1 = init1();

     static {
         System.out.println("trace middle");
     }
     public static final String value2 = init2();


     public static String init1() {
         System.out.println("trace init1");
         return "1";
     }
     public static String init2() {
         System.out.println("trace init2");
         return "2";
     }
 }

will print

将打印

  trace init1
  trace middle
  trace init2

I just tested it and the statics are initialized (=> print) when the class "Statique" is actually used and "executed" in another piece of code (my case I did "new Statique()".

我刚刚对其进行了测试,并且当在另一段代码中实际使用和“执行”类“Statique”时,静态变量被初始化(=> 打印)(我的情况是“new Statique()”。