Почему это объявление переопределяющего метода вызывает ошибку компиляции?

Следующий код:

class Parent {
    public void method(List parameter){
    }
}

class Child extends Parent {

    public void method(List<String> parameter) {
    }
}

не удается скомпилировать со следующей ошибкой:

Parent.java:12: error: name clash: method(List<String>) in Child and method(List) in Parent have the same erasure, yet neither overrides the other
    public void method(List<String> parameter) {
                ^
1 error

Но я проверяю, что JLS8 в §8.4.8.1 говорит:

Метод экземпляра mC, объявленный в классе C или унаследованный им, переопределяет из C другой метод mA, объявленный в классе A, если выполняются все следующие условия:

...

Подпись mC является дополнительной подписью (§8.4.2) подписи mA.

...

А в §8.4.2 говорится:

Сигнатура метода m1 является дополнительной подписью сигнатуры метода m2, если:

...

подпись m1 такая же, как стирание (§4.6) подписи m2.

И в этом случае объявления исходного и замещающего методов имеют одинаковое стирание, так почему же компиляция не выполняется?


person Jaime Hablutzel    schedule 20.09.2016    source источник
comment
List<String> не является стиранием List, поэтому, согласно указанной вами спецификации, это не подпись. Я думаю, вы перепутали m1 и m2.   -  person 4castle    schedule 21.09.2016
comment
Разве они оба не считаются потерянными по типу до List<Object> ?.   -  person Jaime Hablutzel    schedule 21.09.2016
comment
Они оба типа стерты до List, но указанная вами спецификация не о том, имеют ли они общее стирание, а о том, является ли метод подкласса стиранием метода суперкласса. Если бы у родительского класса было List<String>, а у подкласса было List, все было бы в порядке.   -  person 4castle    schedule 21.09.2016
comment
@ 4castle, я понял, я ошибся в своем вопросе, что мне делать? редактировать вопрос? или убрать, так как сам вопрос не был правильно сформулирован ?.   -  person Jaime Hablutzel    schedule 21.09.2016


Ответы (2)


Потому что после стирания типа остается только List (List<Object>, если хотите). Я думаю, вам нужен общий Parent лайк

class Parent<T> {
    public void method(List<T> parameter){
    }
}

class Child extends Parent<String> {
    public void method(List<String> parameter) {
    }
}
person Elliott Frisch    schedule 20.09.2016
comment
Я не уверен, что ваше первое утверждение отвечает на вопрос, потому что OP сделал аналогичный случай, почему это не должно быть ошибкой компилятора. - person 4castle; 21.09.2016
comment
Фактический родительский класс принадлежит устаревшей библиотеке, но в любом случае я на самом деле ищу не решение, а причину, по которой компилятор ведет себя таким образом. - person Jaime Hablutzel; 21.09.2016
comment
@JaimeHablutzel Чтобы унаследованный код (такой, как у вас здесь) продолжал работать с добавлением универсальных типов (которые почти полностью являются системой проверки типов во время компиляции). - person Elliott Frisch; 21.09.2016

И в этом случае объявления исходного и замещающего методов имеют одинаковое стирание, так почему же компиляция не выполняется?

Одного и того же стирания недостаточно. Взгляните еще раз на процитированный вами раздел JLS:

Сигнатура метода m1 является дополнительной подписью сигнатуры метода m2, если:

...

подпись m1 такая же, как стирание (§4.6) подписи m2.

Это не значит, что стирание должны быть одинаковыми. Это означает, что подпись m1 должна быть стиранием подписи m2. Мы не берем здесь стирание подписи m1.

person user2357112 supports Monica    schedule 20.09.2016
comment
В этом случае class Parent { void method(List<String> parameter){ } } class Child extends Parent { void method(List<Object> parameter) { } } должен компилироваться, поскольку подпись m1 совпадает со стиранием подписи m2, но это не так. - person Jaime Hablutzel; 21.09.2016
comment
@JaimeHablutzel: m1 и m2 наоборот. - person user2357112 supports Monica; 21.09.2016
comment
m1 и m2 ссылались на правильные методы, проблема с примером в моем предыдущем комментарии заключалась в том, что стирание типа для List<String> не List<Object>, а просто List. В следующем примере показано, когда m1 is the same as the erasure of the signature of m2, и он работает правильно class Parent { void method(List<String> foo){ } } class Child extends Parent { void method(List bar) { } } . - person Jaime Hablutzel; 21.09.2016
comment
Ваш ответ на самом деле указывает на проблему, формулируя мой вопрос как @ 4castle. Следует ли мне отредактировать вопрос, поскольку он был неправильно сформулирован, или мне следует удалить его, поскольку ваш ответ не будет применяться, если он просто спрашивает Why does this overriding method declaration produce a compilation error? без цитирования JLS (что я неправильно интерпретировал) ?. - person Jaime Hablutzel; 21.09.2016