动态类型的调用方法

Call method of dynamic type

我有一个 class 层次结构,看起来有点像这样:

class Parent { }
class Child1 extends Parent {}
class Child2 extends Parent {}
class Child3 extends Parent {}

在另一个 class 中,我有这样的方法:

void doSomething(Parent p) { //default }
void doSomething(Child1 c) { //implementation for Child 1 }
void doSomething(Child2 c) { //implementation for Child 2 }

目前,当我遇到这样的事情时

Parent p = new Child2();
doSomething(p);

第一个方法,doSomething(Parent)被调用而不是doSomething(Child2)

假设我有一个静态类型为 Parent 和动态类型为 ChildN 的项目列表。我如何确保为动态类型提供的方法被调用,而不进行强制转换。只针对Child3(没有具体的doSomething方法)我想调用默认实现。

您正在查找的内容称为 "multi dispatch or "动态调度" - Java 中不存在。

在Java中,编译器决定在重载的情况下选择哪个方法。 (这就是当您拥有三个名称相同但参数类型不同的方法时会发生的情况)。这发生在编译时,如果您的 "runtime" Parent object 恰好是 Child1 object;没关系。因为编译器 固定 调用的方法 - 如前所述:java 不支持动态调度。

从这个意义上说,正确的 Java 解决方案是在 Parent class 上放置一个方法 "doSomething()";并让每个 child 覆盖 那个方法到特定的东西。

以防 "doSomething()" 没有真正 "fit" 进入这个 class;你可以看看visitor pattern。另一种选择是使用 instanceof ... 但是你应该 "hide" 相应的 if/else 链 ... 再次使用多态性,如:

interface DoIt { void doSomething() }
class ParentDoIt implements DoIt ...
  same for Childs

class DoItFactory {
  DoIt getDoIt(Parent p) {
     if (p instanceof Child1) return new Child1DoIt(p)
     ...

我会这样做。

interface SomeAction { void doSomething(); }

class Parent implements SomeAction { //override doSomething here }
class Child1 extends Parent {//override doSomething here }
class Child2 extends Parent {//override doSomething here }
class Child3 extends Parent { // no need to override here}

现在

在另一个 class 中,我有这样的方法

void doSomething(SomeAction p) { //default }

Parent p = new Child2();
doSomething(p);

p.doSomething(); // would call Child 2

一个解决方案可能是 doSomething 方法使用来自参数的逻辑:

class Parent {
    public void neededMethod() {//default}
}

class Child1 {
    public void neededMethod() {//implementation for Child 1}
}

然后在你的代码中:

void doSomething(Parent p) {
   //more code
   p.neededMethod();
   // code
}

如果此解决方案不适合您,因为您需要某种调度程序,那么您将不得不使用 instanceof,然后调用正确的方法:

void doSomething (Parent p) {
  if (p instanceof Child1) doSomethingWithChild1(p);
  else if (p instanceof Child2) doSomethingWithChild2(p);
  ...
  else defaultSomething(p);
}