public class Main { public static void main(String[] args) { System.out.println(B.x); } } class A { public static String x = "x"; } class B extends A { static { System.out.print("Inside B."); } }
问题:为什么输出将是:“x”。但不是:“内部B.x”java继承的静态初始化
public class Main { public static void main(String[] args) { System.out.println(B.x); } } class A { public static String x = "x"; } class B extends A { static { System.out.print("Inside B."); } }
问题:为什么输出将是:“x”。但不是:“内部B.x”java继承的静态初始化
的参考B.x
问题下面的字节码:
getstatic #3 <Field int B.x>
Java虚拟机指令anewarray,checkcast,getfield命令, getstatic,的instanceof,invokedynamic,invokeinterface ,invokespecial, invokestatic,invokevirtual,ldc,ldc_w,multianewarray,new, put字段,并putstatic使符号引用运行时 常量池。执行任何这些指令需要 分辨率的符号参考。
所以JVM应该可以解决符号引用B.x
。领域分辨率为specified like this:
要在 类或C接口解析为一个场从d未解决的符号引用时,符号引用到C由场 参考给定必须首先被解析(第5.4节。 3.1)。
...
在解决一个字段引用,场分辨率首先尝试 查找的基准场C和其超:
。如果C声明一个字段由 区域基准指定的名称和描述,字段查找成功。声明的字段是字段查找的结果 。
否则,查找字段递归地应用于指定类或接口C的直接 超接口
否则,如果C有一个超类S,场查找施加 递归到S.
否则,字段查找失败。
换句话说,JVM会将B.x
分解为A.x
。这就是为什么只有A
类需要加载。
Class B
延伸A
它有一个public static variable x
,当你调用B.x
如果你希望Inside B.
作为了就把你必须创建一个类的对象,你正在访问。所有的静态代码块都被执行。或者将该静态代码块移动到类A
:-)
当JVM加载类时,它会将所有静态块组合起来,并按它们声明的顺序执行它们。
编辑(Source): 简短的回答是静态不是存在于Java继承。相反,在类中声明的静态成员是(受到“访问”限制的)直接在派生类的名称空间中可见,除非它们被派生类中的声明“隐藏”。
因此,如果静态属于该类只为什么它滴落到 派生类?难道它不应该只与定义为 的类保持一致吗?
是的,但为什么静态块不执行。 –
您不必创建该类的对象来执行静态块。见下面 – durron597
@ durron597我只是告诉一个方式来实现任何方式的问题,我的例子是为什么例子中没有执行静态代码块在派生类中:-) –
因为B.x
实际上是A.x
所以只有A
类需要被加载。
它实际上并不需要加载B
,直到它直接访问B
的静态成员。请注意,此代码:
public class TestMain {
public static void main(String[] args) {
System.out.println(B.x);
System.out.println(B.y);
}
static class A {
public static String x = "x";
}
static class B extends A {
public static String y = "y";
static {
System.out.print("Inside B.");
}
}
}
将输出:
x
Inside B.y
因为它不需要加载B
直到东西B
被访问。
Here's a good link on the subject.从文章中,“不要忘记,这些代码将在JVM加载类时执行,JVM将所有这些块组合成一个静态块,然后执行。 “
所以这看起来像编译器优化,但编译器可以不同。它在某处被描述了吗? –
@ user1839039:我为您添加了一个链接 – durron597
初始化类的包括执行其
static
初始化和初始化在类中声明静态字段(类变量)。[&hellip;]
到
static
字段的引用(§8.3.1.1)仅使类或实际声明它接口初始化时,即使它可能通过一个子类,子接口的名称被称为或者实现接口的类。
因此,尽管—违背权利要求一些上述B
—类的答案也必须加载,以确定B.x
在A
声明,类B
不初始化(即它的static
初始值设定项实际上没有运行),直到你做了一些更具体的B
。
好,但它的行为描述,我的意思是规范呢? –
这不是真的。例如,您可以将静态字段'x'添加到'B',即使您不重新编译'Main',它也会被打印。 – axtavt
@axtavt你是对的。我改变了一下我的答案。 – ShyJ