9
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)

注意: 我知道我是超载而不是骑马。为了更清楚,我编辑了我的问题。

4

5 回答 5

12

该方法在和doThing()中具有不同的方法签名。OneTwo

One.doThing(One one)
Two.doThing(Two two)

因为,签名不匹配,Two.doThing(Two)不覆盖One.doThing(One),因为o是 type OneOne.doThing()被调用。

还要注意的是,One.doThing(One)可以作为asinstance 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)被调用。

于 2013-09-19T12:26:06.133 回答
1

正如你所说,你只是超载

    Two t = new Two();
    One o = t;
    o.doThing(new Two());

即使运行时的实际对象是 Two 对象而不是 One 对象,选择调用哪个重载方法(换句话说,方法的签名)并不是在运行时动态决定的。请记住,引用类型(而不是对象类型)决定了调用哪个重载方法!

当您使用两个对象参数调用 doThing() 方法时,您将调用一个超类 doThing() 方法。doThing() 方法需要一个 One 对象,以及两个 IS-A One。因此,在这种情况下,编译器将 Two 引用扩大到 One 对象,并且调用成功。这里的关键点是引用扩大取决于继承,即 IS-A 测试。

于 2013-09-19T12:47:17.327 回答
1

Java 6 的优秀书籍 SCJP 指出:

如果方法被覆盖,但您使用多态(超类型)引用来引用具有覆盖方法的子类型对象,则编译器假定您正在调用该方法的超类型版本。

所以基本上使用超类型作为参考,你告诉编译器使用超类型方法。

于 2013-09-19T12:59:32.073 回答
0

这是一个棘手的问题我认为
您的陈述
One o = t;
,您假设第一类“o”等于第二类“t”,这实际上并不等于第二类“t”
,因为第二类“t”是从第一类继承的,因此它将在您的情况下分配基类 One,
因此变量 't' 是类 One 的引用,因此将调用类 One 的方法。
此外,您还创建了一个名为 ClassC 的类并尝试设置您的语句
ClassC c= new ClassC ()
,然后
One o = c;
您将收到一个错误...希望能回答您的问题。

于 2013-09-19T13:10:26.717 回答
-1

在编译时,编译器在类中搜索One该方法doThing(Two t),但由于没有具有该签名的方法,因此它开始扩大搜索范围并找到doThing(One o). 然后它保存带有描述符的二进制文件one parameter whose type is One : void。在运行时,由于调用该方法的对象是 type Two,因此在类中Two它会查找与描述符匹配的方法,并且不会搜索doThing接受对象的方法,Two因为它会考虑将调用链接到的二进制文件中的描述符方法doThing(One o)

java规范对解释这一点很有帮助。是链接

于 2014-05-05T08:48:13.503 回答