如果我有一个父子定义了一些方法 .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's foo()
被调用而不是 Parent 的 foo()
.
当我打电话 f.foo(...)
时效果很好作为一个 child ;但如果我从它的父别名引用它,就像 g.foo(...)
中那样然后是父级的foo(..)
无论 arg
的类型如何,都会被调用。
据我了解,我所期望的事情不会发生,因为Java中的方法重载是早期绑定(bind)(即在编译时静态解析),而方法重写是后期绑定(bind)(即在编译时动态解析)并且因为我使用技术上不同的参数类型定义了一个函数,从技术上讲,我使用不同的定义来重载父级的类定义,而不是覆盖它。但我想做的是在概念上“部分压倒一切”。 foo()
的参数是父类 foo()
的子类的论证。
我知道我可以定义存储桶覆盖 foo(Parent arg)
在 Child 中检查 arg 的实际类型是 Parent 还是 Child 并正确传递它,但如果我有 20 个 Child,那将是大量重复的类型不安全代码。
在我的实际代码中,Parent 是一个名为“Function”的抽象类,它只是抛出 NotImplementedException()
。子项包括“多项式”、“对数”等,.foo() 包括 Child.add(Child)、Child.intersectionsWith(Child) 等。并非所有 Child.foo(OtherChild) 的组合都是可解的并且在事实上,甚至不是所有的 Child.foo(Child) 都是可以解决的。因此,我最好定义所有未定义的内容(即抛出 NotImplementedException),然后仅定义那些可以定义的内容。
所以问题是:有没有办法只覆盖父级的 foo() 的一部分?或者有更好的方法来做我想做的事吗?
编辑:
@Zeiss:如果我使用双重调度,如下所示:
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)?
最佳答案
这不是 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());
关于java - Java 中的部分重写(或重载时的动态重写),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2706258/