假设我定义了两个类,Super
和Sub
,Sub
是Super
的子类:
public class Super {}
public class Sub extends Super {}
我知道执行以下操作是合法的:
Super s = new Sub();
但是,我的问题是,编译器认为s
中的引用是什么?它是否认为它只是Super
类型的引用,或者它是否知道它实际上是Sub
类型的引用。我四处寻找类似问题的一些答案,但没有找到任何真正确定的东西。谢谢!
编译器可能出于警告消息的目的"知道"您有一个Sub
实例(因此,如果它看到您将其转换为其他类型,或者不必要地检查它是否为 null,它可能会警告您),但就语言允许和禁止的内容而言,变量只有类型Super
。
(但在运行时,Java 虚拟机当然会知道实例具有运行时类型的Sub
。
您询问的是运行时类型的s
与编译时类型的s
。在编译时,它被认为是一个Super
,因为它就是在代码中声明的方式。但是,在运行时,它被视为Sub
。
为了回答你的问题,让我们添加一些我们类的方法:-
public class Super {
public void superMethod();
}
public class Sub extends Super {
public void childMethod();
}
如果现在我们尝试编译以下行:-
Super s = new Sub();
s.superMethod();
s.childMethod();
在上面的代码最后一行中,不会编译为子方法不存在于类超级中,而只存在于Sub中。因此,编译器没有编译,因为它将 s 引用为 Sub。
编译器仅将其视为Super
。
考虑:
public class Super {}
public class Sub extends Super {
void f() {}
}
请考虑编译以下代码:
Super s = new Sub();
if (s instanceof Sub) {
s.f(); // ERROR: will not compile!
}
即使编译器可以判断正在检查s
的类型,并且在if
块中s
必须是类型Sub
(或某个后代),它仍然不会将s
视为没有显式强制转换的Sub
。
Super s = new Sub();
if (s instanceof Sub) {
((Sub)s).f(); // Now this compiles.
}