Можно ли избежать непроверенных предупреждений при переопределении метода с параметрами необработанного типа?
-
04-07-2019 - |
Вопрос
Я расширяю класс, определенный в библиотеке, который не могу изменить:
public class Parent
{
public void init(Map properties) { ... }
}
Если я определяю класс «Child», который расширяет Parent, и использую Java 6 с дженериками, как лучше всего переопределить метод 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")?
Решение
Да, вы должны объявить переопределяющий метод с той же сигнатурой, что и в родительском классе, без добавления общей информации.
Я думаю, что вам лучше всего добавить аннотацию @SuppressWarnings("unchecked")
к параметру raw-type, а не к методу, чтобы вы не подавили предупреждения общего характера, которые могут быть в вашем собственном коде.
Другие советы
Короткий ответ:нет способа сделать это.
Неудовлетворительный ответ:отключите (конкретные) предупреждения в вашем IDE/build.xml.
Увы, если вы не можете изменить библиотеку, вам придется придерживаться неуниверсальных методов.
Проблема в том, что, несмотря на то, что после стирания типа оба метода init() имеют одинаковую сигнатуру, на самом деле они могут быть разными методами или одинаковыми (*).Компилятор не может определить, следует ли ему выполнять переопределение или перегрузку, поэтому это запрещено.
(*) Предположим, что разработчик библиотеки имел в виду init(Map<String,Integer>).Теперь вы реализуете init(Map<String,String>).Это перегрузка, и в виртуальной таблице дочернего класса должно существовать два метода.
Но что, если разработчик библиотеки имел в виду init(Map<String,String>)?Тогда это переопределяет, и ваш метод должен заменять исходный init в классе Child, и в виртуальной таблице Child будет только один метод.
P.S.Я ненавижу, как Generics реализован в Java :-(
Я думаю, что ответ выше означал бы вместо этого сказать @SuppressWarnings (" rawtypes ").
Вы должны объявить метод с той же сигнатурой, что и у родителя, и, следовательно, вы получите предупреждения при компиляции. Вы можете подавить их с помощью @SuppressWarnings (& Quot; unchecked & Quot;)
Причина, по которой нет способа избавиться от этого, заключается в том, что есть предупреждения, позволяющие вам знать, что можно создавать Коллекции с недопустимыми типами в них. Предупреждения должны исчезнуть только тогда, когда весь код, который может разрешить это, был удален. Поскольку вы наследуете от неуниверсального класса, всегда можно создать коллекцию с недопустимым содержимым. Р>