Вопрос-ответ

Method has the same erasure as another method in type

Метод имеет то же удаление, что и другой метод в type

Почему недопустимо иметь следующие два метода в одном классе?

class Test{
void add(Set<Integer> ii){}
void add(Set<String> ss){}
}

Я получаю compilation error


Метод add(Set) имеет то же удаление add(Set), что и другой метод в type Test.


хотя я могу обойти это, мне было интересно, почему javac это не нравится.

Я вижу, что во многих случаях логика этих двух методов была бы очень похожа и могла быть заменена одним

public void add(Set<?> set){}

метод, но это не всегда так.

Это особенно раздражает, если вы хотите иметь два constructors, которые принимают эти аргументы, потому что тогда вы не можете просто изменить имя одного из constructors.

Переведено автоматически
Ответ 1

Это правило предназначено для предотвращения конфликтов в устаревшем коде, который все еще использует необработанные типы.

Вот иллюстрация того, почему это не было разрешено, взятая из JLS. Предположим, до того, как в Java были введены дженерики, я написал некоторый код, подобный этому:

class CollectionConverter {
List toList(Collection c) {...}
}

Вы расширяете мой класс следующим образом:

class Overrider extends CollectionConverter{
List toList(Collection c) {...}
}

После внедрения generics я решил обновить свою библиотеку.

class CollectionConverter {
<T> List<T> toList(Collection<T> c) {...}
}

Вы не готовы вносить какие-либо обновления, поэтому вы оставляете свой Overrider класс в покое. Чтобы корректно переопределить toList() метод, разработчики языка решили, что необработанный тип "эквивалентен переопределению" любого обобщенного типа. Это означает, что, хотя сигнатура вашего метода больше формально не равна сигнатуре моего суперкласса, ваш метод по-прежнему переопределяет.

Теперь проходит время, и вы решаете, что готовы обновить свой класс. Но вы немного напортачили, и вместо редактирования существующего необработанного toList() метода вы добавляете новый метод, подобный этому:

class Overrider extends CollectionConverter {
@Override
List toList(Collection c) {...}
@Override
<T> List<T> toList(Collection<T> c) {...}
}

Из-за эквивалентности переопределения необработанных типов оба метода находятся в допустимой форме для переопределения toList(Collection<T>) метода. Но, конечно, компилятору необходимо разрешить один метод. Чтобы устранить эту двусмысленность, классам не разрешается иметь несколько методов, эквивалентных переопределению, то есть несколько методов с одинаковыми типами параметров после стирания.

Ключ в том, что это языковое правило, разработанное для поддержания совместимости со старым кодом, использующим необработанные типы. Это не является ограничением, требуемым для удаления параметров типа; поскольку разрешение метода происходит во время компиляции, добавления универсальных типов к идентификатору метода было бы достаточно.

Ответ 2

Java generics использует стирание типов. Бит в угловых скобках (<Integer> и <String>) удаляется, так что в итоге вы получите два метода с идентичной сигнатурой (add(Set) вы видите в ошибке). Это недопустимо, потому что среда выполнения не будет знать, какой использовать в каждом конкретном случае.

Если Java когда-нибудь получит овеществленные дженерики, то вы могли бы это сделать, но сейчас это, вероятно, маловероятно.

Ответ 3

Это связано с тем, что дженерики Java реализованы с стиранием типа.

Ваши методы будут переведены во время компиляции во что-то вроде:

Разрешение метода происходит во время компиляции и не учитывает параметры типа. (см. Ответ Эриксона)

void add(Set ii);
void add(Set ss);

Оба метода имеют одинаковую сигнатуру без параметров типа, отсюда и ошибка.

Ответ 4

Проблема в том, что Set<Integer> и Set<String> фактически обрабатываются как Set из JVM. Выбор типа для набора (String или Integer в вашем случае) - это всего лишь синтаксический сахар, используемый компилятором. JVM не может различать Set<String> и Set<Integer>.

java generics