【问题标题】:Dynamic Polymorphism with Parametrized methods具有参数化方法的动态多态性
【发布时间】:2015-10-23 04:05:58
【问题描述】:

我想对动态多态性有一些清晰的了解。 当子类中的方法被覆盖和重载时,我无法弄清楚方法调用。

这是父类:

父类:

public class Parent {

    void print(Parent parent){
        System.out.println("I am parent classes only print method.");
    }
}

儿童班:

public class Child extends Parent {

    void print(Child child) {
        System.out.println("I am child class' child print method.");
    }


    void print(Parent parent) {
        System.out.println("I am Child class' parent print method ");
    }


}

这是调用者类。

public class Caller {

    public static void main(String[] args) {

        Parent p = new Parent();
        Child c = new Child();
        Parent pc = new Child();

        p.print(p);
        p.print(c);
        p.print(pc);

        c.print(p);
        c.print(c);
        c.print(pc);

        pc.print(p);
        pc.print(c);
        pc.print(pc);

    }

}

我可以在控制台中看到输出,但无法理解方法调用背后的原因。

【问题讨论】:

  • 在我看来,Visitor 很奇怪。
  • “当子类中的方法被覆盖和重载时,我无法弄清楚方法调用。” ...绝不应该是这种情况。 Java 中的重载解析发生在编译时,而不是运行时。如果编译器可以从您的代码中判断要调用哪个方法,那么您也可以。

标签: java polymorphism parametric-polymorphism


【解决方案1】:

工作很简单 - 重载在编译时解决,覆盖在运行时解决(多态性)。

那么,让我们看看在您的每个方法调用中会发生什么...

我们将忽略使用Parent p = new Parent(); 的调用,因为它没有重载或覆盖,所有方法调用都将直接使用父方法"I am parent classes only print method."

还要注意,编译器只关心变量的引用类型。 并且运行时只关心实际对象的类型

因此,在声明Parent pc = new Child() 中,任何关于pc编译时间 决定将引用Parent,而任何关于pc运行时 决定将引用到Child

这是其他方法调用的逻辑,

c.print(p);
//Compiler resolves that `print(Parent)` method should be called.
//Runtime resolves that child objects method should be called.
//Prints "I am Child class' parent print method "

c.print(c);
//Compiler resolves that `print(Child)` method should be called.
//Runtime resolves that child objects method should be called.
//Prints "I am Child class' child print method "

c.print(pc);
//Compiler resolves that `print(Parent)` method should be called.
//Runtime resolves that child objects method should be called.
//Prints "I am Child class' parent print method "

pc.print(p);
//Compiler resolves that `print(Parent)` method should be called.
//Runtime resolves that child objects method should be called.
//Prints "I am Child class' parent print method "

pc.print(c); //PAY ATTENTION TO THIS...
//Compiler resolves that `print(Parent)` method should be called.
// This is because PC is Parent type reference and compiler doesn't find `print(Child)` in Parent class, so it uses `print(Parent)`.
//Runtime resolves that child objects method should be called.
//Prints "I am Child class' parent print method "

pc.print(pc);
//Compiler resolves that `print(Parent)` method should be called.
// This is because Compiler knows only about the variable's reference type (And PC is of type Parent). Hence `print(Parent)` would be chosen.
//Runtime resolves that child objects method should be called.
//During runtime, the type of the actual object is used. And PC is referring to an Child object... So `pc.print(...)` will call the child's method.
//Prints "I am Child class' parent print method "

【讨论】:

  • 您能否更详细地解释一下 pc.print(pc)。因为那会引起混乱。
  • 谢谢。很有用。
【解决方案2】:

我们只考虑两个对象,一个是P(Parent),第二个是C(Child)。现在 P 只能看到它可以访问的那些方法和变量。在我们的例子中,它只能访问父类的打印方法。所以每当你使用父对象调用打印方法时,它只会调用父类的打印方法。

p.print(p);
p.print(c);
p.print(pc);

表示以上所有行将调用父类的打印方法,因为父类无法访问子类的方法。

对于像变量pc这样分配给父对象的子对象,它将调用子类的覆盖方法,即子类的父方法。

pc.print(p);
pc.print(c);
pc.print(pc);

现在对于使用子类C的方法,方法调用有两种可能,一种是接受parent as an argument的print方法,第二种接受child as an argument。所以这一切都取决于你在方法调用中传递的参数。

c.print(p);
c.print(c);
c.print(pc);

在第一次和第三次调用中,您将父对象作为参数传递给方法,因此编译器会根据传递的参数动态识别应该调用哪个方法,因此当父对象传递为时,子类的父方法将被调用一个参数 else 子类的子方法将被调用。

【讨论】:

  • 您的描述有误。 3 个pc. 调用将调用子打印方法,因为覆盖
【解决方案3】:

这个问题看起来与difference-between-method-overloading-and-overriding重复

覆盖(多态性)和重载之间存在核心区别。

覆盖(多态性)在运行时确定。 方法重载在编译时确定。

编译器根据可用的具体类型识别要调用的方法。

所以c.print(c); 是唯一匹配签名的调用:Child.print(final Child child)

【讨论】:

  • 方法覆盖和重载之间的基本区别对我来说很清楚。但我想要明确的运行时方法选择场景。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
  • 2016-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多