2013-05-31 56 views
79
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类的实例变量是final,因为该static块不执行的。静态块不执行

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

哪个存储器将被首先分配,则static final变量或static块?

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

+1

的就是你得到确切的错误和消息? – Patashu

+0

@Patashu,没有错误,它是一个疑问 – Sthita

回答

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

只要你删除final,它不再是一个编译时间常数和上述的特殊行为不适用。 Mno类按照您的预期进行加载,并执行其静态初始化程序。

+1

但是,那么如何在不加载类的情况下评估类中最终变量的值? –

+17

所有评估都在编译时发生,最终结果被硬编码到所有引用变量的地方。 –

+1

因此,如果不是原始变量,而是一些Object,那么这种硬编码将不可能。不是吗?那么,在那种情况下,该类将被加载并且静态块将被执行? –

0

据我所知,它会在出现的顺序执行。例如:

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 

我只是测试它和静力学被初始化(=>打印)时,类“Statique”实际使用并在另一块的“执行”代码(我的情况下,我做了“新Statique()”。

+2

你得到这个输出是因为你通过执行'Statique()'来加载'Statique'类。在提问的时候,'Mno'类完全没有加载。 – RAS

+0

@RAS你绝对正确...... Mno没有加载。 – Sthita

+0

@Fabyen,如果我在测试类中创建Mno对象,如下所示:Mno anc = New Mno();那么它的罚款,但目前的情况下,我没有这样做,我的疑问是,如果我删除最后的静态块执行罚款,否则它不会执行,为什么这样? – Sthita

7

为什么没有加载类是VALfinal它被初始化与a constant expression(9090)的原因。如果,且仅当,这两个条件都得到满足,常量在编译时进行评估,并在需要时进行“硬编码”。

为了防止表情从在编译时被评估(并且使JVM加载类),您可以:

  • 删除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; } 
    
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   

可以“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

1)其实你还没有扩展了MNO类,所以当编译开始就会产生不断变化VAL的,当开始执行时该变量是需要它的负载从memory.so它是不需要你的类引用,以便静态博克不执行。

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