【问题标题】:Why it always invokes parent class method "doTest(double d)"? [duplicate]为什么总是调用父类方法“doTest(double d)”? [复制]
【发布时间】:2017-02-18 05:58:32
【问题描述】:
class PolymorphisomTest {

    class Base {
        public void doTest(double d) {
            System.out.println("From Base");
        }
    }

    class DerivedBase extends Base {

        public void doTest(int d) {
            System.out.println("From Derived Base");
        }
    }

    public void use(Base  base) {
        base.doTest(3);
    }
    public void run() {
        use(new Base());
        use(new DerivedBase ());
    }
    public static void main(String []cmd) {
        new PolymorphisomTest ().run();
    }
}

这里是来自父类的 doTest(double d) 和来自子类的 doTest(int d) 但是当我调用 base.doTest(3) 它总是调用父类方法,即使我的对象引用不同。背后的原因是什么?

【问题讨论】:

  • 如果你使用@Override注解,你会得到一个编译器错误,告诉你你没有覆盖任何东西。
  • 但是当基对象引用是子类时,它也会调用父类方法。为什么它无法调用子类方法,因为我的对象引用了子类
  • 看我的回答。通过将参数类型更改为int,您将创建一个新方法,而不是覆盖父类。
  • Base 只有一个方法doTest(double) 调用的方法的签名是在编译时确定的,而不是运行时。
  • 具有不同签名的方法不会相互覆盖。

标签: java


【解决方案1】:

doTest(double d) 是与void doTest(int d) 完全不同的方法,因为它们有不同的参数列表。实际上根本没有任何多态性。 DerivedBase 正在声明一个新方法,而不是重载 Base.doTest。就好像你已经这样做了:

class Base {
    public void doTest(double d) {
        System.out.println("From Base");
    }
}

class DerivedBase extends Base {
    public void doSomethingElse(int d) {
        System.out.println("From Derived Base");
    }
}

更改参数的类型会更改方法签名,并使其成为新方法,而不是覆盖父类的方法。

当您调用base.doTest(3) 时,编译器将调用doTest(double),因为这是Base 类中唯一与参数匹配的方法。因为该方法没有被任何东西覆盖,Base.doTest 被调用。

【讨论】:

  • 当我通过子类引用调用 base.doTest() 那么参数有什么问题?
  • 如果你想让一个子类覆盖一个方法,它必须有exact相同的nameparameter types,和返回类型。您的子类引用不会覆盖父类方法。
  • use(Base base) 中,将调用的方法签名是在编译时确定的,而不是基于对象的实际运行时类型可能是什么。因此,它必须选择基类中的方法。
  • 我明白你的意思。我个人认为这是方法重载的一种限制
【解决方案2】:

要覆盖方法,您必须匹配派生类中的方法签名。当您从 double 更改为 int 时,您将创建一个新方法。来自Defining Methods - The Java Tutorials

定义:方法声明的两个组成部分包括方法签名——方法的名称和参数类型。

@Override 注释可以保护您免受此类特定错误的影响。你可以这样做,

class DerivedBase extends Base {
    @Override
    public void doTest(double d) {
        System.out.println("From Derived Base");
    }
}

【讨论】:

  • 但是你可以用void method(Object o)覆盖void method(String s),对吧?
  • @slartidan:没有。这不是结束 writing 而是结束 loading
  • “覆盖”一个方法不是一个东西。也许你的意思是“覆盖”,@slartidan?
【解决方案3】:

DerivedBase 类从基类继承了您的 doTest。现在,它有两种方法- doTest (双 d) doTest (int d)

您没有重写方法,而是通过提供不同的参数重载了它。如果您需要覆盖 doTest add 方法,使用 double 作为参数。

它不调用 doTest (int d) 的原因是当我们从父引用调用时,它会在编译时搜索它们的方法并与之绑定。在运行时,它的方法与手头对象的签名相同。

【讨论】:

  • 好的,但我的意思是当我在这里通过 doTest(3) 3 是 int 类型为什么它在子类方法中不匹配
  • 对不起,我在公共汽车上回答迟了,所以保存了部分答案,因为公共汽车在早上休息时停下来
  • 它与子类方法不匹配,因为它是从声明为超类型的变量中调用的。正如@Panther 解释的那样,这是在编译时评估的。因此编译器将参数提升为double 以匹配通过声明的类型 可用的唯一匹配方法。该方法未被覆盖。
猜你喜欢
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 2021-08-24
  • 1970-01-01
  • 2014-01-22
  • 2019-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多