Можно ли избежать отмеченных предупреждений при переопределении метода с параметрами сырого типа?
Я расширяю класс, определенный в библиотеке, которую я не могу изменить:
public class Parent
{
public void init(Map properties) { ... }
}
Если я определяю класс "Ребенок", который расширяет Parent, и я использую Java 6 с generics, как лучше всего переопределить метод init без получения предупреждений без предупреждения?
public class Child extends Parent
{
// warning: Map is a raw type. References to generic type Map<K,V> should be parameterized
public void init(Map properties) { }
}
Если я добавлю общие параметры, я получаю:
// error: The method init(Map<Object,Object>) of type Child has the same erasure as init(Map) of type Parent but does not override it
public void init(Map<Object,Object>) { ... }
// same error
public void init(Map<? extends Object,? extends Object>) { ... }
// same error
public void init(Map<?,?>) { ... }
Эта ошибка возникает независимо от того, используется ли я конкретный тип, ограниченный шаблон или неограниченный шаблон. Есть ли правильный или идиоматический способ переопределить неосновный метод без предупреждений и без использования @SuppressWarnings ( "unchecked" )?
Ответы
Ответ 1
Да, вы должны объявить переопределяющий метод с той же сигнатурой, что и в родительском классе, без добавления информации о генериках.
Я считаю, что лучше всего добавить аннотацию @SuppressWarnings("unchecked")
к параметру raw-type, а не к методу, поэтому вы не будете подавлять другие предупреждения генераторов, которые могут иметься в вашем собственном коде.
Ответ 2
Короткий ответ: нет способа сделать это.
Неудовлетворительный ответ: отключите (конкретные) предупреждения в IDE/build.xml.
Если вы не можете изменить библиотеку, увы, вы должны придерживаться не общих методов.
Проблема заключается в том, что, несмотря на стирание типа, как init() имеют одну и ту же подпись, они могут быть разными способами - или одинаковыми (*). Компилятор не может сказать, должен ли он переопределять или перегружать, поэтому он запрещен.
(*)
Предположим, что разработчик библиотеки означал init (Map < String, Integer > ). Теперь вы выполняете init (Map < String, String > ). Это перегрузка, и в vtable класса Child должны существовать два метода.
Но что, если разработчик библиотеки имел в виду init (Map < String, String > )? Затем он переопределяет, и ваш метод должен заменить оригинальный init в классе Child, и в vtable Child будет только один метод.
P.S. Я ненавижу, как Generics реализованы в Java: - (
Ответ 3
Я думаю, что выше ответ должен был сказать @SuppressWarnings ( "rawtypes" ) вместо этого.
Ответ 4
Вы должны объявить метод с той же сигнатурой, что и родительский, и поэтому при компиляции вы получите предупреждения. Вы можете подавить их с помощью @SuppressWarnings ( "unchecked" )
Причина, по которой невозможно избавиться от этого, заключается в том, что предупреждения содержат информацию о возможности создания в них коллекций с недопустимыми типами. Предупреждения должны уходить только тогда, когда весь код, который может позволить, был удален. Поскольку вы наследуете от не-универсального класса, всегда можно создать коллекцию с недопустимым содержимым.