【问题标题】:Partial overriding in Java (or dynamic overriding while overloading)Java中的部分覆盖(或重载时的动态覆盖)
【发布时间】:2010-04-24 21:36:24
【问题描述】:

如果我有一个父子定义一些方法 .foo() 像这样:

class Parent {
  public void foo(Parent arg) {
    System.out.println("foo in Function");
  }
}
class Child extends Parent {
  public void foo(Child arg) {
    System.out.println("foo in ChildFunction");
  }  
}

当我这样称呼他们时:

  Child f = new Child();
  Parent g = f;
  f.foo(new Parent());
  f.foo(new Child());  
  g.foo(new Parent());
  g.foo(new Child());

输出是:

foo in Parent
foo in Child
foo in Parent
foo in Parent

但是,我想要这个输出:

foo in Parent
foo in Child
foo in Parent
foo in Child

我有一个扩展父类的子类。在 Child 类中,我想“部分覆盖”Parent 的foo(),也就是说,如果参数arg 的类型是 Child,则调用 Child 的 foo() 而不是 Parent 的 foo()

当我小时候打电话给f.foo(...) 时,这行得通;但是如果我从它的父别名中引用它,例如g.foo(...),那么无论arg 的类型如何,都会调用父级的foo(..)

据我了解,我所期望的不会发生,因为 Java 中的方法重载是早期绑定(即在编译时静态解析),而方法覆盖是后期绑定(即在编译时动态解析),因为我用技术上不同的参数类型定义了一个函数,我在技术上用不同的定义重载了父类的定义,而不是覆盖它。但是,当 .foo() 的参数是父级 foo() 的参数的子类时,我想做的是在概念上“部分覆盖”。

我知道我可以在 Child 中定义一个桶覆盖 foo(Parent arg) 来检查 arg 的实际类型是 Parent 还是 Child 并正确传递它,但是如果我有 20 个 Child,那将是大量重复类型不安全的代码。

在我的实际代码中,Parent 是一个名为“Function”的抽象类,它简单地抛出 NotImplementedException()。子项包括“多项式”、“对数”等,.foo() 包括 Child.add(Child)、Child.intersectionsWith(Child) 等。并非所有 Child.foo(OtherChild) 的组合都是可解的并且在事实上,甚至不是所有 Child.foo(Child) 都是可解决的。所以我最好先定义所有未定义的东西(即抛出 NotImplementedException),然后只定义那些可以定义的东西。

所以问题是:有没有办法只覆盖父级的 foo() 的一部分?还是有更好的方法来做我想做的事?

编辑

@Zeiss:如果我使用 Double Dispatch,像这样:

class Parent {
  public void foo(Parent arg) {
    System.out.println("foo in Parent");
  }
}
class Child extends Parent {
  public void foo(Parent arg) {
    System.out.println("foo in Child(Parent)");
    arg.foo(this);
  }
  public void foo(Child arg) {
    System.out.println("foo in Child(Child)");
  }
}

我得到了无限递归:

(stack): 
StackOverflowError: ...
...
    at sketch_apr25a$Child.foo(sketch_apr25a.java:35)
...
(output):
...
foo in Child(Parent)
...

在执行g.foo(new Child()); 时。其余的似乎都很好,因为输出是:

foo in Child(Parent)
foo in Parent

foo in Child(Child)

foo in Child(Parent)
foo in Parent

foo in Child(Parent)
(infinite recursion follows)

为什么会这样? g 是 Parent 的别名,但它正在访问 Child 的 foo(Parent)?

【问题讨论】:

    标签: java dynamic overloading overriding


    【解决方案1】:

    这不是Double Dispatching 的用例吗?


    更新:

    class Function {
        public void add(Function f) {
            f.addMe(this);
        }
    
        public void addMe(Function f) {
            // Default case
            throw NotImplementedException();
        }
        public void addMe(Logarithmic log) {
            // Code that handles the real
        }
    }
    
    class Logarithmic extends Function {
        // This object supports adding
        public void add(Function f) {
            f.addMe(this);
        }
    }
    
    
    Logarithmic log = new Logarithmic();
    log.add(new Function()); 
    log.add(new Logarithmic()); 
    
    Function f = log;
    f.add(new Function()); 
    f.add(new Logarithmic()); 
    

    【讨论】:

    • 我考虑过 Double Dispatch,但这给了我无限递归。我可能没有正确使用它,请检查更新的问题。
    • 在您的编辑中,您覆盖(在子项中)父项中的方法,因此您称自己。您的问题比 Wikipedia 中描述的 Double Dispatch Pattern 复杂一些,因为您已经将对象作为参数传递。请参阅我尝试解决的示例代码。也许这对你有点帮助。
    • 我已经尝试了一些变体,但所有这些都需要函数了解对数、多项式等。Double Dispatch 的使用是父(或更一般地是服务)提供者)不必知道他们的孩子是谁(更一般地说是服务用户),所以我认为它接近我想要的;我会继续“实验”(因为缺乏有意识的设计,现在想得太累了)并保持更新这个线程。
    【解决方案2】:

    我通过像这样在Child 中显式覆盖foo(Parent arg) 来让它工作-

    class Parent {
        public void foo(Parent arg) {
            System.out.println("foo in Parent");
        }
    }
    
    class Child extends Parent {
        @Override
        public void foo(Parent arg) {
            System.out.println("foo in Child(Parent)");
            if (arg instanceof Child) {
                foo((Child)arg);
            } else {
                super.foo(arg);
            }
        }
        public void foo(Child arg) {
            System.out.println("foo in Child(Child)");
        }
    }
    

    这似乎符合

    的逻辑

    我想“部分覆盖”Parent 的 foo(),也就是说,如果参数 arg 的类型是 Child,则调用 Child 的 foo() 而不是 Parent 的 foo()。

    但不是“部分覆盖”该方法,您实际上必须覆盖该方法。

    【讨论】:

    • 但如果我有(比如说)二十个孩子,那意味着我必须将此覆盖代码复制到二十个孩子,这就是我说“大量重复类型-不安全的代码”。如果类型不安全的代码被本地化到一个点(例如,Parent),它可能是可以接受的。 (是的,我认为instanceof 类型不安全,因为它会干扰类型系统)
    猜你喜欢
    • 2023-01-08
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2013-04-05
    • 2022-01-10
    • 2010-10-24
    相关资源
    最近更新 更多