Java中的静态块没有执行
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); } }
我知道一个static
块加载类时执行。 但是在这种情况下,类Mno
的实例variables是final
,因为static
块没有执行。
为什么? 如果我将删除final
,它会工作正常吗?
哪个内存将被首先分配, static final
variables还是static
块?
如果由于final
访问修饰符类没有得到加载,那么variables如何获得内存?
- 一个
static final int
字段是一个编译时常量 ,它的值被硬编码到目标类中,而不参考它的原点; - 因此你的主类不会触发包含该字段的类的加载;
- 因此该类中的静态初始化程序不会被执行。
在具体的细节上,编译的字节码对应于这个:
public static void main(String arg[]){ System.out.println("**MAIN METHOD"); System.out.println(9090) System.out.println(9190) }
只要删除final
,它不再是编译时常量,上面描述的特殊行为不适用。 Mno
类按照您的预期进行加载,并执行其静态初始化程序。
该类未被加载的原因是VAL
是final
,并且用常量expression式 (9090)进行初始化。 当且仅当满足这两个条件时,才在编译时评估常量,并在需要时进行“硬编码”。
为了防止在编译时评估expression式(并使JVM加载你的类),你可以:
-
删除最后的关键字:
static int VAL = 9090; //not a constant variable any more
-
或者将右边的expression式改为非常量(即使variables仍然是最终的):
final static int VAL = getInt(); //not a constant expression any more static int getInt() { return 9090; }
如果你看到使用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
你可以清楚地看到在“ 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); } }
1)实际上你没有扩展那个Mno类,所以当编译开始时,它会产生variablesVAL的常量,当执行开始时,该variables是需要加载它从memory.so它不需要你的类的引用,使静态程序块不执行。
2)如果一个类扩展了那个Mno类,那么这个静态块被包含在A类中的话,那么这个静态块就被执行了。 例如.. public class A extends 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); } }
据我所知,它将按照外观顺序执行。 例如 :
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"; } }
将打印
trace init1 trace middle trace init2
我刚刚testing过,静态被初始化(=>打印),当“Statique”类被实际使用并且在另一段代码中“执行”时(我的例子是“新Statique()”)。