2016-12-15 72 views
0

说,我有两个类定义,SuperSubSubSuper一个子类:超类引用变量所持有的引用的类型是什么?

public class Super {} 
public class Sub extends Super {} 

我知道它是合法执行以下操作:

Super s = new Sub(); 

我的问题,虽然,编译器认为s中的参考文献是什么?它是否认为它只是Super类型的参考,还是它知道它实际上是Sub类型的参考。我已经四处寻找类似的问题的答案,但还没有发现任何真正的权威。谢谢!

+1

编译thinka超级只有 – Panther

+1

没有@Manishsakpal编译器只知道变量类型是超级。没有实际的对象 – Panther

+1

是@panther我知道编译器意识到只有变量类型是Super,但我忘了提及,在运行时这是引用Sub类型的对象。抱歉,是我的错。 –

回答

1

编译器可能会为警告消息“知道”您有一个Sub的实例(因此,如果它看到您将其转换为其他类型或不必要地检查它是否为空,它可能会发出警告),但根据语言允许和禁止的内容,变量只有Super

(但在运行,当然,Java虚拟机就会知道实例具有运行时类型Sub。)

1

您在询问的是s的运行时类型与s的编译时类型。在编译时,它被认为是Super,就像它在代码中声明的那样。但是在运行时,它被视为Sub

1

要回答你的问题,让我们来添加我们的类的一些方法: -

public class Super { 
     public void superMethod(); 
} 
public class Sub extends Super { 
     public void childMethod(); 
} 

如果现在我们尝试编译这些下面几行: -

Super s = new Sub(); 
s.superMethod(); 
s.childMethod(); 

在上面的代码中最后一行,不会编译为childMethod不存在于Class super中,但仅在Sub中存在。所以,编译器不会编译,因为它将s引用为Sub。

1

编译器认为它只能作为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. 
}