Java 方法局部内部类与内部类
下面的代码生成输出Java 方法局部内部类与内部类,java,inner-classes,Java,Inner Classes,下面的代码生成输出middle。有人能详细解释这是怎么发生的吗 是因为class A的“内部”版本声明是在go()方法中创建class A的实例之后进行的吗 class A { void m() { System.out.println("outer"); } } public class MethodLocalVSInner { public static void main(String[] args) { new MethodLoc
middle
。有人能详细解释这是怎么发生的吗
是因为class A
的“内部”版本声明是在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");
}
}
}
我猜您希望调用本地类方法。这并没有发生,因为您使用的
newa()
超出了本地类的范围。因此,它访问范围中下一个更接近的候选对象,即内部类。发件人:
直接由块(§14.2)封闭的局部类声明的范围是直接封闭块的其余部分,包括其自身的类声明
因此,方法第一行中的newa()
将不会访问它后面出现的本地类。如果在此之前移动类声明,将获得预期的输出
另请参见,其中包含类似的示例。由于代码的顺序,您将获得“中间”输出。由于在调用
newa()
之后发生了作用域为class A
的方法,因此得到的输出是“中间”。如果按如下顺序切换,您将获得“内部”输出:
输出:
内部
实例化A类的优先顺序从高到低为:
有关更多信息,请查看官方网站。您正在使用
MethodLocalVSInner
内围棋法
您正在创建A()
在这里,由于您没有显式导入外部A类
,而直接内部类位于方法调用语句之后,因此JVM正在选择内部类A
,该类位于MethodLocalVSInner
的类级别,并在该类内部执行go方法案例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();
}
在这种情况下,它将打印内部
,因为类现在在范围内。在方法中:
void go() {
new A().m();
class A {
void m() {
System.out.println("inner");
}
}
}
当方法开始执行时,将执行第一行
newa().m()代码>
因为内部类已经在作用域中,所以将创建该类的对象,并且将为内部类
调用m
方法,而不是为本地方法类
,因为它仍然不在作用域中。这就是为什么要将中间作为输出
但如果您将方法更改为:
void go() {
class A {
void m() {
System.out.println("inner");
}
}
new A().m();
}
您的本地方法类现在将在范围内,并且将具有更高的首选项,因此您将立即获得输出内部
内部
无法打印的原因是():
由块直接封闭的局部类声明的范围是直接封闭块的其余部分,包括它自己的类声明
(在方法中声明的类称为局部类。)
因此A
不能引用本地类,因为表达式newa()
发生在其声明之前。换句话说,局部类的作用域与局部变量相似
打印中间类而不是外部类的原因是内部类A
将顶层类A
()隐藏起来:
名为n
的类型的声明d
隐藏了d
范围[…]内名为n
的任何其他类型的声明
这意味着MethodLocalVSInner
主体中的任何地方,非限定A
必须引用内部类
如果您熟悉成员变量的阴影,例如:
class Example {
int x;
void setX(int x) {
// ┌ 'x' refers to the local method parameter
this.x = x;
}
}
本质上,类声明也是如此。尝试将内部类A
重命名为B
,您将得到外部
输出。这应该给你一个提示。@TimBiegeleisen我很难选择一个特定的答案,因为你的许多答案都是正确的和切中要害的。你会在eclipse IDE中得到一个警告,类型a从未在本地使用过,也就是说,在方法go
中定义的本地类A
从未被使用过。我很想知道您是为哪个需求实现这个功能的?或者这只是一个棘手的问题@KisHanSarsecHaGajjar在解决一本书中的一些练习,我发现了这个问题。OP也猜到了。但为什么呢?请备份您的答案。然后找到证明它的JLS引用-目前这只是猜测。@Tim Biegeleisen您能告诉我为什么在新的A().m()之前声明类会将其带到范围并打印内部吗?正如@Radiodef在他的答案中指出的,只要您在块中定义本地类A
,该类的作用域是该定义之后(而不是之前)块的其余部分。至于Java架构师为什么决定这样做,那是另一个问题。@TimBiegeleisen实际上我希望答案中包括这一点。因为这是我想知道的。这与类加载无关。第二次执行该方法时,即使本地类a已加载,它仍将生成相同的输出。这也是由于作用域首选项的缘故。这就像方法,然后是类@ErwinBolwidt我现在已经更改了它。@Radiodef好吧,缺少什么?@RohitJain你能告诉我为什么在new A().m()之前声明这个类吗
将其带到作用域,并打印出内部
@kissarsechagajjar为什么要写这么多感叹号?@Ramswaroop您的问题的答案可能只是Java架构师选择了本地类以这种方式运行。@Ramswaroop我想我引用的JLS部分,关于作用域解释
class Example {
int x;
void setX(int x) {
// ┌ 'x' refers to the local method parameter
this.x = x;
}
}