以下代码生成输出middle
。谁能详细解释这是怎么回事?
是因为class A
的“内部”版本的声明是在class A
方法中创建go()
的实例之后发生的吗?
class A {
void m() {
System.out.println("outer");
}
}
public class MethodLocalVSInner {
public static void main(String[] args) {
new MethodLocalVSInner().go();
}
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
class A {
void m() {
System.out.println("middle");
}
}
}
答案 0 :(得分:38)
我猜你期望调用本地类方法。这没有发生,因为你在本地类的范围之外使用new A()
。因此,它访问范围中的下一个更接近的候选者,即内部类。来自JLS §6.3:
由块(第14.2节)直接包含的本地类声明的范围是直接封闭块的其余部分,包括它自己的类声明。
因此,方法第一行中的new A()
将不会访问其后出现的本地类。如果在此之前移动类声明,您将获得预期的输出。
另见JLS §14.3,其中包含类似示例。
答案 1 :(得分:17)
您正在获得输出"中间"因为您拥有代码的顺序。由于方法范围class A
在您对new A()
的调用后出现,因此您将获得输出" middle"。如果您按如下方式切换订单,您将获得输出" inner":
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
<强>输出:强>
inner
从高到低实例化class A
的优先顺序是:
有关详细信息,请查看官方Java Language Specification discussing inner classes。
答案 2 :(得分:7)
inner
未打印的原因是(6.3):
由块直接包含的本地类声明的范围是直接封闭块的其余部分,包括它自己的类声明。
(在方法中声明的类称为本地类。)
因此A
无法引用本地类,因为表达式new A()
在声明之前发生。换句话说,本地类与局部变量具有相似的范围。
middle
打印而不是outer
的原因是内部类A
阴影顶级类A
({{ 3}}):
名为
d
的类型的声明n
会影响名为n
的{{1}}范围内的任何其他类型的声明。
这意味着d
正文中的任何位置,不合格的MethodLocalVSInner
必须引用内部类。
如果您熟悉成员变量的阴影,例如:
A
基本上同样的事情是继续进行类声明。
答案 3 :(得分:4)
案例1:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
在这种情况下,如果您在本地类的范围之外运行您的方法。这就是为什么它会打印middle
案例2:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
在这种情况下,它将打印inner
因为类现在在范围内。
答案 4 :(得分:2)
:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
当方法开始执行时,将执行第一行
new A().m();
因为内部类已经在范围内,所以将创建该类的对象,并且m
将调用inner class
方法而不是local method class
,因为它仍然不在范围内。这就是为什么你得到middle
作为输出。
但如果您将方法更改为:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
您的本地方法类现在将在范围内并具有更高的首选项,因此您现在将获得输出inner
。
答案 5 :(得分:1)
您正在使用go
MethodLocalVSInner
方法
go方法内部
您正在创建A()
的实例
这里因为你没有显式地导入外部A class
,而直接内部类是在方法调用语句之后,JVM正在选择类inner class A
的{{1}}并执行go