当运行以下代码时,它会根据语言规范的要求打印"X.Q"
而不是"A<T>.X.Q"
。
class A<T> {
static class X {
static class Q {
public static void main() {
System.out.println("A<T>.X.Q");
}
}
}
}
class B extends A<B.Y.Q> {
static class Y extends X {
} // X here is inherited from A
}
class X {
static class Q {
public static void main() {
System.out.println("X.Q");
}
}
}
public class Test {
public static void main(String[] args) {
B.Y.Q.main();
}
}
有人可以帮助我理解这个程序的输出是什么,根据我的理解它应该是"A<T>.X.Q"
而不是"X.Q"
,请纠正我,如果我弄错了某些地方
答案 0 :(得分:5)
您获得"X.Q"
打印的原因是X
指的是作为未命名包的作用域X
,而不是A<T>.X
。 &#34;外面&#34;无关紧要。 X
在 B
之后被声明为,因为Java编译器在解析B.Y
基类的名称之前会看到它。
您可以在代码中强制继承A.X
,如下所示:
class B extends A<B.Y.Q> {
static class Y extends A.X {
} // ^^
// Add this
}
修改:(感谢user695022评论)
奇怪的是,如果外部类不是通用的,问题就会消失:
class A {
static class X {
static class Q {
public static void main() {
System.out.println("A<T>.X.Q");
}
}
}
}
答案 1 :(得分:2)
好的,让我们看看你在这里有什么。根据我的理解,你的论点基本上是Y extends X
但X
。默认情况下访问外部作用域。如果删除外部X
,则无法编译,因为X
不可用。对于内部静态类,您必须放置显式import语句或在扩展时使用完全限定名称引用它。
这是分辨率的默认约定。如果您意识到在外部作用域中只能有一个具有相同名称的类,但是您可以拥有许多具有相同名称的内部静态类,那么这也是有意义的。您需要一个约定访问所有人这些。此约定以看似直观的方式解决了这个问题(否则,您必须在扩展时键入所有X
的完全限定名称)
如果您考虑外部的那个,它应该打印"X.Q"
它。
答案 2 :(得分:1)
Q的方法主要打印X.Q是被调用的方法,因为B.Y扩展了X(不是A.X),其Q方法隐藏了A.X.Q.main方法。
跟进起来有点困惑,只需添加跟踪或逐步调试即可看到完整的调用树。