动态类型的调用方法

时间:2016-06-17 07:22:17

标签: java dynamic-typing

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

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

在另一个课程中,我的方法看起来像这样:

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方法)我想调用默认实现。

3 个答案:

答案 0 :(得分:3)

您正在寻找的是“多调度或”动态调度“ - 并且在Java中不存在。

在Java中,编译器决定在重载的情况下选择哪种方法。 (当你有三个具有相同名称但参数类型不同的方法时会发生这种情况)。这发生在编译时,如果你的“运行时”父对象碰巧是Child1对象;没关系。因为编译器修复要调用的方法 - 如上所述:java不支持动态调度。

从这个意义上讲,正确的Java解决方案是在您的Parent类中放置一个方法“doSomething()”;并让每个孩子覆盖该方法到特定事物。

如果“doSomething()”并不真正“适合”这个类;你可以看一下visitor pattern。另一个选择是使用instanceof ...但是你应该使用多态来“隐藏”相应的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)
     ...

答案 1 :(得分: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);
}

答案 2 :(得分:0)

我会这样做。

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}

现在

在另一个课程中,我的方法看起来像这样

void doSomething(SomeAction p) { //default }

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

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