Если у меня есть родитель-потомок, который определяет какой-то метод .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 я хочу "частично переопределить" foo()
Родителя, то есть, если тип аргумента arg
- Child, тогда вызывается Child * foo()
вместо foo()
.
Родителя.
Это работает нормально, когда я позвонил f.foo(...)
как ребенок; но если я ссылаюсь на него из псевдонима Родителя, например, в g.foo(...)
, тогда Родитель foo(..)
будет вызываться независимо от типа arg
.
Насколько я понимаю, то, что я ожидаю, не произойдет, потому что перегрузка метода в Java является ранним связыванием (то есть разрешается статически во время компиляции), в то время как переопределение метода является поздним связыванием (то есть разрешается динамически во время компиляции), и так как я Определяя функцию с технически другим типом аргумента, я технически перегружаю определение класса Parent определением, а не переопределяю его. Но то, что я хочу сделать, это концептуально «частично переопределить», когда аргумент foo()
является подклассом аргумента foo()
родителя.
Я знаю, что могу определить переопределение сегмента foo(Parent arg)
в Child, которое проверяет, является ли фактический тип arg Parent или Child, и передает его правильно, но если у меня есть двадцать 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 - псевдоним Родителя, но он обращается к дочернему элементу foo (Родителю)?