aily121211
2020-01-13 01:27
采纳率: 100%
浏览 385

Java中指向子类的父类对象调用子类重载的方法,传入指向子类对象的父类引用,为什么最终还是调用了父类的方法?

Dog类实现了Animal接口,Animal a = new Dog(); 创建子类对象,a指向的应该是一个Dog类的对象,a.bark(d); 调用的应该是Dog重载的bark方法才对,可为什么最终调用的还是接口Animal的方法呢。

public interface Animal {
    default void bark(Animal a) {
        System.out.println("Animal");
    }
}

public class Dog implements Animal {
    // Overload
    public void bark(Dog d) {
        System.out.println("Dog");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        Dog d = new Dog();
        a.bark(a); // Animal
        a.bark(d); // Animal

        d.bark(a); // Animal
        d.bark(d); // Dog
    }
}
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

6条回答 默认 最新

  • 已采纳
    1. a是一个Animal类型引用,调用方法时,编译器会先去Animal类中的虚函数表中找有没有可以调用的方法。编译器找到Animal中的bark方法,而bark并没有被Dog实现,且Animal中的bark方法参数类型为Animal,而Dog为Animal的实现类,所以函数可以使用,于是编译器偷了个懒就不去Animal类的虚函数表中去匹配方法了,所以a.bark(d),调用的是接口中的方法。

    2. 而d是一个Dog类型引用。编译器会先去Dog类的虚函数表中找有没有可以调用的方法,找到Dog中的bark方法和Animal中的bark方法,因为参数d为Dog类型,固根据参数匹配原则选择Dog类中的bark方法。

    3. 总的来说,接口类型的引用,优先使用接口中没被实现且可以用的方法。在Animal类的虚函数表中,只有Animal的bark方法地址,没有Dog中的bark方法地址。

    4. 深究可以去看看虚函数表,不过这个概念只在C++中存在,而java和C++本是同根生。

    5. 原创手打,忘采纳。

    已采纳该答案
    打赏 评论
  • 农夫丶果园 2020-01-13 09:14

    可能是因为这俩不是一个方法吧 ,他们的方法参数不一样 , 我感觉你把Override注释掉是不是因为编辑器给你提示报错说这里不能使用Override , 因为他们不是同一个方法,你把方法的参数都去掉就行了, 反正这个方法的参数你也没有用到

    打赏 评论
  • 一名剑客 2020-01-13 09:46

    因为方法重写没有成功,输入参数可以放大但不能缩小,你把public void bark(Dog d) 中的Dog改成Animal就可以了

    打赏 评论
  • 家明君 2020-01-13 09:49

    Animal a = new Dog(); 是dog实现了Animal 类的接口 调用的自然是 Animal的, 为什么bark()可以传递Dog 应该是dog是 Animal的实现类(Animal a = new Dog(); )。,没有更好的解释,如果有大神可以通知我一下。

    打赏 评论
  • threenewbee 2020-01-13 10:43

    Java语言不支持重写方法的协变(Contravariant)
    也就是public void bark(Dog d)只能定义为
    public void bark(Animal d)
    你非要那么写,则两个bark是不同的方法,不构成覆盖,只能是重载而已。

    打赏 评论
  • 「已注销」 2020-01-13 11:52

    楼上回答的很正确,同时补充一下如果你要是想a也调用子类的方法应该再次使用向下转型Dog a1 = (Dog)a;这个时候调用的是子类方法

    打赏 评论

相关推荐 更多相似问题