Java中的部分覆盖(或重载时的动态覆盖)

时间:2010-04-24 21:36:24

标签: java dynamic overloading override

如果我有一个父子,它定义了一些方法.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

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

当我作为一个孩子打电话给f.foo(...)时,这很好用;但如果我从g.foo(...)中的父别名引用它,那么无论foo(..)的类型如何,都会调用父arg

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

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

在我的实际代码中,Parent是一个名为“Function”的抽象类,它只抛出foo(Parent arg)。这些孩子包括“多项式”,“对数”等,而.foo()包括Child.add(Child),Child.intersectionsWith(Child)等等。并非Child.foo(OtherChild)的所有组合都是可解决的。事实上,甚至所有Child.foo(儿童)都无法解决。所以我最好定义所有未定义的内容(即抛出NotImplementedException),然后只定义那些可以定义的内容。

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

编辑

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

NotImplementedException()

我得到了无限的递归:

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());

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

2 个答案:

答案 0 :(得分:3)

这不是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()); 

答案 1 :(得分:0)

我通过明确覆盖foo(Parent arg)中的Child来实现这一点 -

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()。

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