【问题标题】:Call method of dynamic type动态类型的调用方法
【发布时间】:2016-06-17 07:22:16
【问题描述】:

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

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

【问题讨论】:

    标签: java dynamic-typing


    【解决方案1】:

    您要查找的内容称为“多分派”或“动态分派”——Java 中不存在。

    在 Java 中,编译器决定在 重载 的情况下选择哪种方法。 (这就是当您拥有三个具有相同名称但参数类型不同的方法时会发生的情况)。这发生在编译时,如果您的“运行时”Parent 对象恰好是 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)
         ...
    

    【讨论】:

      【解决方案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);
      }
      

      【讨论】:

        【解决方案3】:

        我会这样做的。

        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
        

        【讨论】:

        • 谢谢,我会这样做,但我无法编辑我的父类或子类
        • @Karl 是的,在这里你可能需要修改父类实现接口和另一个类。如果不可能,那么您可能必须使用 instanceof 进行检查,这会降低性能。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-05-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-05
        • 1970-01-01
        • 2020-04-03
        相关资源
        最近更新 更多