а также
есно, почему это корректное переопределение:
public abstract class A {
public abstract <X> Supplier<X> getSupplier();
public static class B extends A {
@Override
public Supplier<String> getSupplier() {
return String::new;
}
}
}
Тогда как это не так:
public abstract class A {
public abstract <X> Supplier<X> getSuppliers(Collection<String> strings);
public static class B extends A {
@Override
public Supplier<String> getSuppliers(Collection<String> strings) {
return String::new;
}
}
}
Согласно сJLS §8.4.8.1, B.getSupplier
должна быть подписьA.getSupplier
:
Метод экземпляра mC, объявленный или унаследованный классом C, переопределяет из C другой метод mA, объявленный в классе A, если все следующее верно:
...Подпись mC является подписью (§8.4.2) подписи mA....Подписи определены вJLS §8.4.2:
Два метода или конструктора, M и N, имеютта же подпись если они имеют одинаковое имя, одинаковые параметры типа (если они есть) (§8.4.4) и после адаптации формальных параметров типа N к параметрам типа M одинаковые формальные параметры.
Сигнатура метода m1 является подписью метода m2, если либо:
m2 имеет такую же подпись, как m1, илиподпись m1 такая же, как стирание (§4.6) подписи m2.Так похожеB.getSupplier
это подписьA.getSupplier
ноB.getSuppliers
являетсяне подписьA.getSuppliers
.
Интересно, как это может быть.
ЕслиB.getSupplier
это подписьA.getSupplier
потому что он имеет то же самое стирание, тоB.getSuppliers
также должно иметь такое же стирание, что иA.getSuppliers
, Этого должно хватить для переопределенияgetSuppliers
быть законным - но это не так.
ЕслиB.getSupplier
это подписьA.getSupplier
поскольку он имеет одну и ту же сигнатуру, мне интересно, что именно означает «параметры одного типа (если они есть)».
Если рассматриваются параметры типа, то они должны иметь разные параметры типа:A.getSupplier
имеет параметр типаX
, B.getSupplier
не имеет ни одного
Если параметры типа не учитываются, то какgetSuppliers
разные?
Это скорее академический вопрос о переопределениях и обобщениях, поэтому, пожалуйста, не предлагайте рефакторинг кода (например, параметр типа перемещения).X
в класс и т. д.).
Я ищу формальный ответ на основе JLS.
С моей точки зренияB.getSupplier
не должно быть в состоянии переопределитьA.getSupplier
поскольку они не имеют одинаковые параметры типа. Это делает следующий код (который производитClassCastException
) законно:
A b = new B();
URL url = b.<URL>getSupplier().get();