Java-дженерики называют clash, имеет такое же стирание
У меня есть суперкласс 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.
Что я делаю неправильно?
6 ответов
Вы переопределяете saveAll
метод с несовместимым типом. Возможно, вы хотите сделать что-то вроде:
public class Bar extends Foo<MyClass>
Функция в Foo<E>
protected void saveAll(Collection<E> many)
и функционировать в баре:
public void saveAll(Collection<MyClass> stuff) {
super.saveAll(stuff);
}
Из-за функции стирания типов в Java JVM не сможет узнать, является ли этот метод параметризованным типом MyClass или первым, который должен быть вызван.
Если возможно или применимо, наиболее часто используемый шаблон, который я видел, чтобы избежать этого, это изменение класса Foo
иметь параметризованный тип:
public class Foo<T> {
protected void saveAll(Collection<T> many) {}
}
а затем Бар просто реализовать Foo
для вашего конкретного типа:
public class Bar extends Foo<MyClass> {
public void saveAll(Collection<MyClass> many) {
super.saveAll(many);
}
}
Во время выполнения типы параметров заменяются на 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> {
}
Когда компиляторы компилируются в байтовый код, происходит процесс, называемый 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) {
}
Вы просто переопределяете методы с разными сигнатурами.
Хорошей идеей будет использование правила PECS (производитель - расширяет, потребитель - супер), описанного во второй редакции Effective Java Джошуа Блоха.
согласно этому правилу это должно выглядеть так.
В классе Foo:
public class Foo<E>{
protected void saveAll(Collection<? super E> many){....}
protected void getAll(Collection<? extends E> many){....}
}
Хотя существующие ответы верны, эта ошибка легко возникает, когда вы объявляете фактический тип не в "extends
... ", но в фактическом имени класса:
Неправильно:
public class Bar<MyClass> extends Foo
{
...
}
Правильный:
public class Bar extends Foo<MyClass>
{
...
}