Имя генерации дженериков Java, имеет такое же стирание
У меня есть суперкласс Foo. И класс-бар, расширяющий его.
public class Bar extends Foo
Функция в Foo:
protected void saveAll(Collection<?> many)
Функция в баре:
public void saveAll(Collection<MyClass> stuff) {
super.saveAll(stuff);
}
Получение ошибки:
Name clash: The method saveAll(Collection<MyClass>) of type Bar has the same erasure as saveAll(Collection<?>) of type Foo but does not override it.
Что я делаю неправильно?
Ответы
Ответ 1
Вы переопределяете метод saveAll
несовместимым типом. Возможно, вы хотите сделать что-то вроде:
public class Bar extends Foo<MyClass>
Функция в Foo<E>
protected void saveAll(Collection<E> many)
и функция в баре:
public void saveAll(Collection<MyClass> stuff) {
super.saveAll(stuff);
}
Ответ 2
Из-за функции стирания типа Java Java JVM не сможет узнать, является ли это метод с параметризованным типом MyClass или первым, который должен быть вызван.
Если возможно или применимо, наиболее часто используемый шаблон, который я видел, чтобы избежать этого, заключается в том, чтобы изменить класс Foo
, чтобы иметь параметризованный тип:
public class Foo<T> {
protected void saveAll(Collection<T> many) {}
}
а затем Bar просто реализует Foo
для вашего конкретного типа:
public class Bar extends Foo<MyClass> {
public void saveAll(Collection<MyClass> many) {
super.saveAll(many);
}
}
Ответ 3
Во время выполнения типы параметров заменяются на Object
.
Итак, saveAll(Collection<?>)
и saveAll(Collection<MyClass>)
преобразуются в saveAll(Collection)
. Это столкновение имен.
Подробнее см. здесь.
Вы можете сделать это:
public class Foo<T> {
protected void saveAll(Collection many) {
// do stuff
}
}
public class Bar extends Foo<MyClass> {
}
Ответ 4
Когда компиляторы компилируются в байтовый код, происходит процесс с именем Erasure. Это удаляет информацию о типе из коллекций. Я считаю, что он будет вручную выполнять трансляции и т.д. Как часть процесса генерации байтового кода. Если вы удалите общие части своего класса (например, <.. > ), вы увидите, что у вас есть два метода saveAll. Ошибка в том, что у вас есть два варианта сохранения всех методов. Коллекции имеют объект типа в байтовом коде.
Попробуйте удалить <.. > , который может сделать его более понятным. Когда вы вернете <... > назад, рассмотрите имя методов. Если они разные, они должны компилироваться.
Также я не думаю, что это проблема спящего режима, поэтому этот тег следует удалить. У вас есть общая проблема java.
Что вы можете сделать здесь: введите класс
public class Bar extends Foo<MyClass>
а затем типы методов с T
public void saveAll(Collection<MyClass> stuff) {
super.saveAll(stuff);
}
а затем объявление Foo будет чем-то вроде
public abstract class Bar extends Foo<T> {
public void saveAll(Collection<T> stuff) {
}
Ответ 5
Вы просто переопределяете методы с разными сигнатурами.
Будет хорошей идеей использовать правило PECS (Producer - Extends, Consumer - Super), описанное в "Эффективном Java Second Edition" Джошуа Блоха.
в соответствии с этим правилом он должен выглядеть следующим образом.
В классе Foo:
public class Foo<E>{
protected void saveAll(Collection<? super E> many){....}
protected void getAll(Collection<? extends E> many){....}
}
Ответ 6
В то время как существующие ответы верны, эта ошибка возникает, когда вы объявляете фактический тип не в разделе "extends
...", а в имени фактического класса:
Неправильно:
public class Bar<MyClass> extends Foo
{
...
}
Правильно:
public class Bar extends Foo<MyClass>
{
...
}