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());
}
}
结果:一个
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)
。如果有人解释,我会很高兴
在第二段代码中,它打印“Two”。
问题:从超类引用调用时,它正在调用doThing(One o)
从子类引用调用时,它调用doThing(Two o)
注意:我知道我超载而不是骑行。为了更清晰,我编辑了我的问题。
答案 0 :(得分:12)
方法doThing()
在One
和Two
中有不同的方法签名。
One.doThing(One one)
Two.doThing(Two two)
由于签名不匹配,Two.doThing(Two)
不会覆盖One.doThing(One)
,而o
的类型为One
,因此会调用One.doThing()
。
另外需要注意的是,One.doThing(One)
可以将instance of Two
作为One.doThing(One)
的参数Two extends One
。
基本上,“@ nachokk - 你正在超载,而不是覆盖”
在第一个场景中,当你做到了
Two t = new Two();
One o = t;
o.doThing(new Two());
因此,o
是One
的一个实例,Two.doThing(Two)
无法使用o
因此调用One.doThing(One)
在第二种情况下,
Two t = new Two();
One o = t;
t.doThing(new Two());
t
是Two
的一个实例,因此会调用Two.doThing(Two)
。
答案 1 :(得分:1)
正如你所说的那样,你只是超载
Two t = new Two();
One o = t;
o.doThing(new Two());
即使运行时的实际对象是Two对象而不是One对象,也是如此 选择哪个重载方法调用(换句话说,签名的 方法)不是在运行时动态决定的。请记住,参考 type(不是对象类型)确定调用哪个重载方法!
当您使用两个对象参数调用doThing()方法时,您将调用一个超类doThing()方法.doThing()方法需要一个One对象和两个IS-A One。 因此,在这种情况下,编译器扩展了对One对象的两个引用,并且 调用成功。这里的关键点是参考扩展取决于 继承,换句话说是IS-A测试。
答案 2 :(得分:1)
优秀的SCJP for Java 6声明:
如果方法被覆盖但是你使用了多态(超类型) 引用用重写方法引用子类型对象, 编译器假设你正在调用的超类型版本 方法
所以基本上使用supertype作为参考,你告诉编译器使用超类型方法。
答案 3 :(得分:0)
这是一个棘手的问题
你的声明
One o = t;
我想,你假设一级'o'等于二级't',它实际上不等于二级't'
因为Class Two't'是继承自Class One,所以它将在你的情况下分配基类One,
因此变量't'是类One的引用,因此将调用类One的方法。
更多的是你创建了一个名为ClassC类的类,并尝试设置你的语句
ClassC c= new ClassC ()
然后
One o = c;
您将收到错误...希望您的问题得到答案。
答案 4 :(得分:-1)
在编译时,编译器在类One
中搜索方法doThing(Two t)
,但由于没有具有该签名的方法,因此它开始扩展其搜索并找到doThing(One o)
。然后它保存带有描述符one parameter whose type is One : void
的二进制文件。在运行时,因为调用该方法的对象的类型为Two
,所以在类Two
中,它会查找与描述符匹配的方法,而不会搜索接受对象的方法doThing
Two
,因为它考虑二进制文件中的描述符,它将调用链接到方法doThing(One o)
。
java规范对此有很大帮助。 here是链接