方法局部内部 class 与内部 class
Method local inner class vs inner class
下面的代码产生输出 middle
。谁能详细解释这是怎么回事?
是不是因为class A
的"inner"版本的声明是在go()
方法中创建了class 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");
}
}
}
我猜您希望调用本地 class 方法。这并没有发生,因为您在本地 class 范围之外使用 new A()
。因此,它访问范围内的下一个更接近的候选者,即内部 class。来自 JLS §6.3:
The scope of a local class declaration immediately enclosed by a block (§14.2) is the rest of the immediately enclosing block, including its own class declaration.
因此,第一行方法中的new A()
,将不会访问其后出现的本地class。如果您在此之前移动 class 声明,您将获得预期的输出。
另请参阅 JLS §14.3,其中包含类似示例。
您得到的输出是 "middle",因为您拥有代码的顺序。由于方法作用域 class A
在您调用 new A()
之后 发生 ,您将获得输出 "middle"。如果按如下方式切换顺序,您将得到输出 "inner":
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
输出:
inner
实例化class A
的优先顺序从高到低是:
- 阻止
- 方法
- class
- 套餐
请查看官方Java Language Specification discussing inner classes了解更多信息。
您正在使用 MethodLocalVSInner
的实例调用 go
方法
go 方法内部
您正在创建 A()
的实例
在这里,由于您没有显式导入外部 A class
并且直接内部 class 在方法调用语句之后,JVM 选择 inner class A
,它位于 class 级别 MethodLocalVSInner
并在里面执行 go 方法
案例 1:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
在这种情况下,如果您 运行 您的方法超出了本地 class 的范围。这就是为什么它会打印 middle
案例 2:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
在这种情况下,它将打印 inner
因为 class 现在在范围内。
在方法中:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
当方法开始执行时,第一行将被执行
new A().m();
并且因为内部 class 已经在范围内,所以将创建 class 的对象,并且将为 inner class
而不是 [=15] 调用 m
方法=] 因为它仍然不在范围内。这就是为什么你得到 middle
作为输出。
但如果您将方法更改为:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
您的本地方法 class 现在将在范围内并且具有更高的优先级,因此您现在将获得输出 inner
。
未打印 inner
的原因是 (6.3):
The scope of a local class declaration immediately enclosed by a block is the rest of the immediately enclosing block, including its own class declaration.
(在方法内部声明的 class 称为局部 class。)
所以A
不能引用局部class,因为表达式new A()
发生在它的声明之前。换句话说,局部 classes 具有与局部变量类似的作用域。
打印 middle
而不是 outer
的原因是内部 class A
shadows 是顶层class A
(6.4.1):
A declaration d
of a type named n
shadows the declarations of any other types named n
that are in scope […] of d
.
这意味着在MethodLocalVSInner
的主体中的任何地方,不合格的A
必须引用内部class。
如果您熟悉成员变量的隐藏,例如:
class Example {
int x;
void setX(int x) {
// ┌ 'x' refers to the local method parameter
this.x = x;
}
}
class 声明本质上是一样的。
下面的代码产生输出 middle
。谁能详细解释这是怎么回事?
是不是因为class A
的"inner"版本的声明是在go()
方法中创建了class 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");
}
}
}
我猜您希望调用本地 class 方法。这并没有发生,因为您在本地 class 范围之外使用 new A()
。因此,它访问范围内的下一个更接近的候选者,即内部 class。来自 JLS §6.3:
The scope of a local class declaration immediately enclosed by a block (§14.2) is the rest of the immediately enclosing block, including its own class declaration.
因此,第一行方法中的new A()
,将不会访问其后出现的本地class。如果您在此之前移动 class 声明,您将获得预期的输出。
另请参阅 JLS §14.3,其中包含类似示例。
您得到的输出是 "middle",因为您拥有代码的顺序。由于方法作用域 class A
在您调用 new A()
之后 发生 ,您将获得输出 "middle"。如果按如下方式切换顺序,您将得到输出 "inner":
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
输出:
inner
实例化class A
的优先顺序从高到低是:
- 阻止
- 方法
- class
- 套餐
请查看官方Java Language Specification discussing inner classes了解更多信息。
您正在使用 MethodLocalVSInner
go
方法
go 方法内部
您正在创建 A()
的实例
在这里,由于您没有显式导入外部 A class
并且直接内部 class 在方法调用语句之后,JVM 选择 inner class A
,它位于 class 级别 MethodLocalVSInner
并在里面执行 go 方法
案例 1:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
在这种情况下,如果您 运行 您的方法超出了本地 class 的范围。这就是为什么它会打印 middle
案例 2:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
在这种情况下,它将打印 inner
因为 class 现在在范围内。
在方法中:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
当方法开始执行时,第一行将被执行
new A().m();
并且因为内部 class 已经在范围内,所以将创建 class 的对象,并且将为 inner class
而不是 [=15] 调用 m
方法=] 因为它仍然不在范围内。这就是为什么你得到 middle
作为输出。
但如果您将方法更改为:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
您的本地方法 class 现在将在范围内并且具有更高的优先级,因此您现在将获得输出 inner
。
未打印 inner
的原因是 (6.3):
The scope of a local class declaration immediately enclosed by a block is the rest of the immediately enclosing block, including its own class declaration.
(在方法内部声明的 class 称为局部 class。)
所以A
不能引用局部class,因为表达式new A()
发生在它的声明之前。换句话说,局部 classes 具有与局部变量类似的作用域。
打印 middle
而不是 outer
的原因是内部 class A
shadows 是顶层class A
(6.4.1):
A declaration
d
of a type namedn
shadows the declarations of any other types namedn
that are in scope […] ofd
.
这意味着在MethodLocalVSInner
的主体中的任何地方,不合格的A
必须引用内部class。
如果您熟悉成员变量的隐藏,例如:
class Example {
int x;
void setX(int x) {
// ┌ 'x' refers to the local method parameter
this.x = x;
}
}
class 声明本质上是一样的。