【问题标题】:Why is the super class method called?为什么要调用超类方法?
【发布时间】:2013-09-19 12:21:37
【问题描述】:
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)

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

【问题讨论】:

  • 你是重载,而不是覆盖
  • @nachokk :如果您已发布此链接作为答案,我会选择您作为已接受的答案。我从没想过要查找 Java 规范。谢谢,伙计.. dat 帮了大忙..
  • 没关系,但您要查看的是动态方法调用的工作原理。
  • 我浏览了整个文档.. :)

标签: java


【解决方案1】:

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

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());

所以,oOne 的一个实例,而Two.doThing(Two) 不适用于o,因此调用One.doThing(One)

在第二种情况下,

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

tTwo 的一个实例,因此会调用Two.doThing(Two)

【讨论】:

  • 这很好,但如果他在One 类中重载方法,那么doThing(Two two) 将被调用!。
  • 感谢回复.. 但我很清楚我并没有过度骑行.. 请查看我编辑的问题.. 也许我之前的问题不清楚.. 跨度>
  • @BlackPanther 查看我的更新答案,希望它可以理解。
【解决方案2】:

Java 6 的优秀书籍 SCJP 指出:

如果一个方法被覆盖但你使用了多态(超类型) 使用覆盖方法引用子类型对象的引用, 编译器假定您正在调用 方法。

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

【讨论】:

  • 我不明白这个.. 该方法没有覆盖。你能举个例子说明你用代码说的话吗?
【解决方案3】:

正如你所说,你只是超载

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

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

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

【讨论】:

  • 所以您是说即使调用该方法的对象是Two 类型,该方法也会被调用它的引用选择和绑定?
【解决方案4】:

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

【讨论】:

    【解决方案5】:

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

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

    【讨论】:

    • @downvoter:请让我知道为什么答案没有用.. 如果可能的话,我可以改进它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    • 2011-04-16
    • 2018-08-22
    • 2019-10-05
    • 2020-02-14
    • 1970-01-01
    • 2012-04-25
    相关资源
    最近更新 更多