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
访问修饰符导致类没有加载,那么变量如何获取内存?
答案 0 :(得分:132)
static final int
字段是编译时常量,其值被硬编码到目标类中,而不引用其原点; 具体细节,编译后的字节码对应于:
public static void main(String arg[]){
System.out.println("**MAIN METHOD");
System.out.println(9090)
System.out.println(9190)
}
一旦删除final
,它就不再是编译时常量,并且上述特殊行为不适用。正如您所期望的那样加载Mno
类,并执行静态初始化程序。
答案 1 :(得分:8)
未加载课程的原因是VAL
为final
AND ,初始化为a constant expression(9090)。如果且仅当满足这两个条件时,在编译时评估常量并在需要时“硬编码”。
为防止在编译时计算表达式(并使JVM加载您的类),您可以:
删除最终关键字:
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; }
答案 2 :(得分: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);
}
}
答案 3 :(得分:1)
1)实际上你还没有扩展那个Mno类,所以当编译开始时它将生成变量VAL的常量,当执行开始时需要该变量来自memory.so它的负载它不需要你的类引用以便静态的bock没有执行。
2)如果A类在那时扩展了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);
}
}
答案 4 :(得分: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”类并在另一段代码中“执行”时,静态(=> print)被初始化(我的情况下,我做了“new Statique()”。