java为什么调用超类方法?
class One {
public void doThing(One o) {System.out.println("One");}
}
class Two extends One{
public void doThing(Two t) {System.out.println("Two");}
}
public class Ugly {
public static void main(String[] args) {
Two t = new Two();
One o = t;
o.doThing(new Two());
}
}
结果:1
class One {
public void doThing(One o) {System.out.println("One");}
}
class Two extends One{
public void doThing(Two t) {System.out.println("Two");}
}
public class Ugly {
public static void main(String[] args) {
Two t = new Two();
One o = t;
t.doThing(new Two());
}
}
结果:两个
我知道,在运行时,即使对象引用是超类类型,实际的对象类型也是已知的,并且会调用实际对象的方法。但是如果是这种情况,那么在运行时应该调用doThing(Two t)
方法,而不是调用超类方法doThing(One o)
。如果有人解释一下,我会很高兴的
在第二段代码中,它打印“2”
问题:从超类引用调用时,它正在调用doThing(One o)
从子类引用调用时,它正在调用doThing(Two o)
注意:我知道我超载了,而不是骑过头了。为了更清晰,我对我的问题进行了编辑
# 1 楼答案
方法
doThing()
在One
和Two
中具有不同的方法签名因为签名不匹配,
Two.doThing(Two)
不会覆盖One.doThing(One)
,并且因为o
是One
类型,所以调用One.doThing()
还需要注意的是
One.doThing(One)
可以将instance of Two
作为One.doThing(One)
asTwo extends One
的参数在第一个场景中
所以,
o
是One
的一个实例,Two.doThing(Two)
对o
不可用,因此调用One.doThing(One)
在第二种情况下
t
是Two
的一个实例,因此Two.doThing(Two)
被调用# 2 楼答案
在编译时,编译器在类
One
中搜索方法doThing(Two t)
,但由于没有具有该签名的方法,因此它开始扩大搜索范围并找到doThing(One o)
。然后它用描述符one parameter whose type is One : void
保存二进制文件。在运行时,由于调用该方法的对象的类型为Two
,因此在类Two
中,它会查找与描述符匹配的方法,而不会搜索接受Two
对象的方法doThing
,因为它认为二进制文件中的描述符将调用链接到方法doThing(One o)
java规范非常有助于解释这一点here是链接
# 3 楼答案
这是一个棘手的问题
你的立场
One o = t;
我想,你是在假设一级'o'等于二级't',这实际上并不等于二级't'
由于类2“t”是从类1继承而来的,因此在您的情况下,它将分配基类1,
所以变量't'是类1的引用,因此将调用类1的方法。
再创建一个名为ClassC class的类,并尝试设置语句
ClassC c= new ClassC ()
然后
One o = c;
你会得到一个错误。。。希望你的问题能得到答案
# 4 楼答案
正如你所说,你只是超载了
尽管运行时的实际对象是两个对象而不是一个对象,但 选择要调用的重载方法(换句话说,是 方法)在运行时不是动态决定的。记住,参考资料 类型(而不是对象类型)决定调用哪个重载方法
当使用两个对象参数调用doThing()方法时,将调用一个超类doThing()方法。doThing()方法需要一个One对象,而Two IS-a-One。 因此,在本例中,编译器将两个引用扩展到一个对象 调用成功。这里的关键点是,参考加宽取决于 换句话说,继承是一种考验
# 5 楼答案
优秀的书籍SCJP for Java 6指出:
所以,基本上使用超类型作为参考,就是告诉编译器使用超类型方法