方法本地内部类与内部类
下面的代码产生输出middle
。 任何人都可以详细解释这是怎么发生的?
是否因为class A
的“内部”版本的声明是在go()
方法中创buildclass A
的实例之后发生的?
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"); } } }
我猜你希望本地类方法被调用。 这并没有发生,因为你在本地类的范围之外使用new A()
。 因此,它访问下一个更接近的范围内的候选人,这将是内部类。 来自JLS§6.3 :
立即封闭的本地类声明的范围(第14.2节)是立即封闭块的其余部分,包括它自己的类声明。
因此,方法第一行中的new A()
不会访问出现在其后面的本地类。 如果您在此之前移动类声明,您将获得预期的输出。
另请参阅JLS第14.3节 ,其中包含相似的示例。
由于您拥有代码的顺序,您将得到输出“中间”。 由于方法范围的class A
在调用new A()
之后发生,因此您将得到输出“middle”。 如果您按照以下顺序切换顺序,您将得到输出“内部”:
void go() { class A { void m() { System.out.println("inner"); } } new A().m(); }
输出:
inner
实例化class A
的优先顺序从高到低依次为:
- 块
- 方法
- 类
- 包
请看官方Java语言规范讨论内部类的更多信息。
inner
不打印的原因是( 6.3 ):
立即封闭的本地类声明的作用域是立即封闭的块的其余部分,包括它自己的类声明。
(在方法中声明的类称为本地类。)
所以A
不能引用本地类,因为expression式new A()
发生在它的声明之前。 换句话说,本地类与局部variables的范围相似。
middle
打印而不是outer
的原因是内部类A
影响顶层类A
( 6.4.1 ):
名为
n
的types的声明d
隐藏d
的作用域中名为n
的任何其他types的声明。
这意味着在MethodLocalVSInner
体内的任何地方,不合格的A
必须引用内部类。
如果您熟悉成员variables的阴影,例如:
class Example { int x; void setX(int x) { // ┌ 'x' refers to the local method parameter this.x = x; } }
基本上,类声明正在进行。
情况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
becase类现在在范围内。
在方法中:
void go() { new A().m(); class A { void m() { System.out.println("inner"); } } }
当方法开始执行时,第一行将执行new A().m();
并且由于内部类已经在范围内,因此该类的对象将被创build,并且m
方法将被调用inner class
而不是local method class
因为它仍然不在范围内。 这就是为什么你作为输出middle
。
但如果你改变你的方法为:
void go() { class A { void m() { System.out.println("inner"); } } new A().m(); }
你的本地方法类现在将在范围内,并将有更高的偏好,所以你会得到输出inner
。
您正在使用MethodLocalVSInner
的实例调用go
方法
在go方法里面,你在这里创build一个A()
的实例,因为你没有明确地导入外部的A class
而直接的内部类是在方法调用语句之后,JVM正在挑选inner class A
,它在MethodLocalVSInner
并执行里面的go方法