Интересно, почему это допустимое переопределение:
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) сигнатуры мА.
- ...
Подписи определены в 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 чтобы переопределить 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();