当子类对象被转换为其超类时,例如
Superclass obj = new Subclass();
并定义了类
public class Superclass{
public void thisMethod(){
System.out.println("Superclass version was executed");
}
和
public class Subclass extends Superclass{
public void thisMethod(){
System.out.println("Subclass version was called");
}
public void newMethod(){
System.out.println("blah");
}
}
当调用obj.thisMethod()
时,我得到Subclass version was called
作为输出,这显然意味着在子类中定义的此方法的版本(原始超类对象不能的版本"执行")被调用,虽然声明的类型是超类,是吗?
所以,即使子类方法是在obj上执行的,
调用obj.newMethod()
时,出现编译错误。
基本上,为什么子类中定义的thisMethod()
版本是通过超类对象obj
调用的?我知道obj
的实际类型仍然是Subclass,所以很自然地应该调用新版本,但是,我不应该调用obj.newMethod()
吗?
感谢大家的解释(:
编辑:意味着在标题中覆盖*
答案 0 :(得分:7)
基本上,为什么子类中定义的thisMethod()的版本是通过Superclass对象obj调用的?
因为它基本上是继承点 - 它允许实现覆盖,而调用代码不需要知道正在使用哪个实现。以InputStream
为例 - 您可以使用InputStream
进行编码,然后无论您是否通过FileInputStream
,ByteArrayInputStream
等,相同的代码都会有效。在抽象类或接口的情况下,您可能正在调用在编译时类型中没有具有任何实现的方法 - 但它保证会出现这样的情况。是在执行时使用的具体对象类型的实现。
我知道obj的实际类型仍然是Subclass,所以很自然地,应该调用新版本,但是,我不应该调用
obj.newMethod()
吗?
不,因为obj
的编译时类型为Superclass
。区分变量的编译时类型(确定哪些方法可用)和对象的执行时类型非常重要变量的值引用,它确定实际调用哪些方法实现。
这只是一个非常简短的描述 - 你应该阅读一本好的Java书籍关于继承的章节以获取更多细节。
答案 1 :(得分:1)
理论上obj
是指向Superclass
对象的Subclass
引用。
对于编译器obj
只是Superclass
,因此可以调用所有Superclass
方法,例如thisMethod
,编译器不知道对象的类型,只知道引用的类型,因此编译器将拒绝newMethod
,因为它无法证明此方法存在。
但是在运行时,对象的类型用于分派方法而不是引用类型,因此thisMethod
将被解析为Subclass
的版本。
现在,如果我们知道运行时对象的类型为Subclass
,我们想告诉编译器这个,我们做一个强制转换:
Subclass subobj = (Subclass) obj;
之后,编译器知道subobj
类型为Subclass
,并且接受调用newMethod
,转换只是编译器的信息,并且不会改变任何内容对象obj
,obj
不是Subclass
,前一个语句将在运行时抛出ClassCastException
。
答案 2 :(得分:0)
超类obj = new Subclass()在这个定义中你只能在Superclass.And中的公开方法实际上指向Subclass对象,当你调用任何方法时它会调用子类实现