java-方法本地内部类与内部类
下面的代码产生输出class A。谁能详细解释这是怎么发生的?
是否因为在go()方法中创建class A的实例之后才出现29737083357170170768的“内部”版本声明?
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");
}
}
}
6个解决方案
38 votes
我猜您期望本地类方法被调用。 那没有发生,因为您正在使用new A()超出本地类的范围。 因此,它访问范围内的下一个更接近的候选对象,即内部类。 根据JLS§6.3:
紧接在块中的局部类声明的范围(第14.2节)是紧随其后的块的其余部分,包括它自己的类声明。
因此,方法的第一行中的new A()将无法访问其后出现的本地类。 如果在此之前移动类声明,则将获得预期的输出。
另请参见JLS§14.3,其中包含类似的示例。
Rohit Jain answered 2020-07-19T18:49:26Z
17 votes
由于代码的顺序,您将获得“中间”输出。 由于在调用class A之后发生了方法范围为297370921642020142014的情况,因此您将获得输出“ middle”。 如果按以下方式切换顺序,则将获得输出“ inner”:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
输出:
class A
从高到低实例化class A的优先顺序为:
块
方法
类
包
请查看有关内部类的正式Java语言规范,以获取更多信息。
Tim Biegeleisen answered 2020-07-19T18:50:17Z
7 votes
无法打印MethodLocalVSInner的原因是(6.3):
一个块紧紧包围的局部类声明的范围是紧紧包围的块的其余部分,包括它自己的类声明。
(在方法内部声明的类称为本地类。)
因此MethodLocalVSInner无法引用本地类,因为表达式A出现在声明之前。 换句话说,局部类的作用域与局部变量相似。
打印MethodLocalVSInner而不是A的原因是内部类n遮盖了顶级类d(6.4.1):
类型为A的声明MethodLocalVSInner遮盖了范围为d的任何其他类型的名为n的声明。
这意味着在MethodLocalVSInner正文中的任何位置,不合格的A必须引用内部类。
如果您熟悉成员变量的影子,例如:
class Example {
int x;
void setX(int x) {
// ┌ 'x' refers to the local method parameter
this.x = x;
}
}
本质上,类声明也是如此。
Radiodef answered 2020-07-19T18:51:13Z
4 votes
情况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,因为该类现在在范围内。
Sumit Singh answered 2020-07-19T18:51:46Z
2 votes
在方法中:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
当方法开始执行时,将执行第一行inner
并且因为内部类已经在范围内,所以将创建该类的对象,并且将为inner class而不是为local method class调用inner方法,因为它仍不在范围内。 这就是为什么您得到middle作为输出的原因。
但是如果您将方法更改为:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
您的本地方法类现在将在范围内,并且具有更高的优先级,因此您现在将获得输出inner。
Prashant answered 2020-07-19T18:52:23Z
1 votes
您正在使用A class的实例调用A()方法
里面的方法您正在创建A()的实例在这里,因为您没有显式导入外部A class,并且直接内部类位于方法调用语句之后,所以JVM选择了MethodLocalVSInner的类级别的inner class A,并在其中执行go方法
Thusitha Thilina Dayaratne answered 2020-07-19T18:52:48Z