超类引用变量持有的引用类型是什么?



假设我定义了两个类,SuperSubSubSuper的子类:

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.
}

最新更新