Ковариация и перегрузка в Java
class A {
boolean f(A a) { return true; }
}
class B extends A {
boolean f(A a) { return false; } // override A.f(A)
boolean f(B b) { return true; } // overload A.f
}
void f() {
A a = new A();
A ab = new B();
B b = new B();
ab.f(a); ab.f(ab); ab.f(b); //(1) false, false, *false*
b.f(a); b.f(ab); b.f(b); //(2) false, false, true
}
Не могли бы вы объяснить первую строку последнего ложного вывода, почему это не так?
Ответы
Ответ 1
Не могли бы вы объяснить первую строку последнего ложного вывода, почему это не так?
Тип времени компиляции ab
равен A
, поэтому компилятор, который выполняет разрешение перегрузки, определяет, что единственная действительная сигнатура метода f(A a)
, поэтому она вызывает это.
Во время выполнения эта подпись метода выполняется как B.f(A a)
, потому что B
переопределяет ее.
Всегда помните, что подпись выбрана во время компиляции (перегрузка), но реализация выбирается во время выполнения (переопределение).
Ответ 2
Ну.. потому что вы вызываете тип A. Поэтому вы можете вызывать только версию f (A a). что возвращает false в B.
Ответ 3
Поскольку вы используете тип объекта A, вы можете вызывать только f (A A). Потому что B отменяет его.
Ответ 4
Не могли бы вы объяснить первую строку последнего ложного вывода, почему это не так?
Подумайте иначе: -
попробуйте комментировать ниже в классе B (главный код)
boolean f(A a) { return false; } // override A.f(A)
и добавьте syso в класс A в этом методе → boolean f(A a){....}
Затем вы увидите, что ab.f(A a)
или ab.f(B b)
будет вызывать метод f(A a)
только класса A.
Поскольку ab имеет тип A.
Также обратите внимание: вы не сможете вызвать какой-либо метод класса B также из объекта ab.
Надеюсь, что это добавит больше разъяснений к вышеприведенным блестящим ответам.
Наконец, вы можете искать это сейчас → Почему мы назначаем родительскую ссылку на дочерний объект в Java?