Вопрос:

Тип безопасности: непроверенный актерский состав

java spring type-safety unchecked

319961 просмотра

10 ответа

4168 Репутация автора

В моем весеннем контексте приложения у меня есть что-то вроде:

<util:map id="someMap" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.String">
    <entry key="some_key" value="some value" />
    <entry key="some_key_2" value="some value" />   
</util:map>

В классе Java реализация выглядит следующим образом:

private Map<String, String> someMap = new HashMap<String, String>();
someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");

В Eclipse я вижу предупреждение, которое гласит:

Безопасность типов: непроверенное приведение из объекта в HashMap

Что я сделал не так? Как мне решить проблему?

Автор: DragonBorn Источник Размещён: 04.11.2008 04:29

Ответы (10)


235 плюса

22620 Репутация автора

Решение

Ну, во-первых, вы тратите память на новый HashMapвызов создания. Ваша вторая строка полностью игнорирует ссылку на этот созданный hashmap, делая его доступным для сборщика мусора. Итак, не делайте этого, используйте:

private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");

Во-вторых, компилятор жалуется, что вы приводите объект к HashMapбез проверки, является ли он HashMap. Но, даже если вы должны были сделать:

if(getApplicationContext().getBean("someMap") instanceof HashMap) {
    private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
}

Вы, вероятно, все еще получите это предупреждение. Проблема в том, что getBeanвозвращается Object, поэтому неизвестно, что это за тип. Преобразование в HashMapнапрямую не вызовет проблемы во втором случае (и, возможно, в первом случае не будет предупреждения, я не уверен, насколько педантичен компилятор Java с предупреждениями для Java 5). Тем не менее, вы конвертируете его в HashMap<String, String>.

HashMaps - это действительно карты, которые принимают объект в качестве ключа и имеют объект в качестве значения, HashMap<Object, Object>если хотите. Таким образом, нет никакой гарантии, что когда вы получите свой bean-компонент, он может быть представлен как, HashMap<String, String>потому что вы могли бы иметь это, HashMap<Date, Calendar>потому что возвращаемое неуниверсальное представление может иметь любые объекты.

Если код компилируется, и вы можете выполнить его String value = map.get("thisString");без ошибок, не беспокойтесь об этом предупреждении. Но если карта не полностью содержит строковые ключи к строковым значениям, вы получите ClassCastExceptionво время выполнения, потому что в этом случае обобщения не могут блокировать это.

Автор: MetroidFan2002 Размещён: 04.11.2008 04:44

27 плюса

6570 Репутация автора

Предупреждение только это. Предупреждение. Иногда предупреждения не имеют значения, иногда нет. Они привыкли обращать ваше внимание на то, что компилятор считает проблемой, но может и не быть.

В случае приведения это всегда дает предупреждение в этом случае. Если вы абсолютно уверены, что конкретное приведение будет безопасным, то вам следует рассмотреть возможность добавления аннотации, подобной этой (я не уверен в синтаксисе) непосредственно перед строкой:

@SuppressWarnings (value="unchecked")
Автор: David M. Karr Размещён: 04.11.2008 04:44

9 плюса

18319 Репутация автора

Вы получаете это сообщение, потому что getBean возвращает ссылку на объект, и вы приводите его к правильному типу. Java 1.5 дает вам предупреждение. Такова природа использования Java 1.5 или выше с кодом, который работает следующим образом. Spring имеет типобезопасную версию

someMap=getApplicationContext().getBean<HashMap<String, String>>("someMap");

в его списке задач.

Автор: David Nehme Размещён: 04.11.2008 04:44

290 плюса

1124078 Репутация автора

Проблема в том, что приведение является проверкой во время выполнения, но из-за стирания типа во время выполнения на самом деле нет разницы между a HashMap<String,String>и HashMap<Foo,Bar>любым другим Fooи Bar.

Используйте @SuppressWarnings("unchecked")и держите нос. Ох, и кампания за усовершенствованные дженерики на Java :)

Автор: Jon Skeet Размещён: 04.11.2008 05:09

77 плюса

786 Репутация автора

Как показывают вышеприведенные сообщения, список нельзя различить между a List<Object>и a List<String>или List<Integer>.

Я решил это сообщение об ошибке для аналогичной проблемы:

List<String> strList = (List<String>) someFunction();
String s = strList.get(0);

со следующим:

List<?> strList = (List<?>) someFunction();
String s = (String) strList.get(0);

Объяснение: Первое преобразование типов проверяет, что объект является списком, не заботясь о типах, содержащихся в нем (поскольку мы не можем проверить внутренние типы на уровне списка). Второе преобразование теперь требуется, потому что компилятор знает только, что List содержит какие-то объекты. Это проверяет тип каждого объекта в списке по мере его доступа.

Автор: Larry Landry Размещён: 14.11.2012 09:46

5 плюса

70 Репутация автора

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

Например, если вы пытаетесь использовать

private Map<String, String> someMap = new HashMap<String, String>();

Вы можете создать новый класс, такой как

public class StringMap extends HashMap<String, String>()
{
    // Override constructors
}

Затем, когда вы используете

someMap = (StringMap) getApplicationContext().getBean("someMap");

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

Автор: Rabbit Размещён: 13.04.2016 03:55

1 плюс

19572 Репутация автора

Другим решением, если вы часто используете один и тот же объект и не хотите засорять свой код @SupressWarnings("unchecked"), было бы создание метода с аннотацией. Таким образом, вы централизуете составление и, надеюсь, уменьшаете вероятность ошибки.

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}
Автор: Jeremy Размещён: 20.10.2016 07:25

1 плюс

646 Репутация автора

Ниже приведен код причины Тип безопасности Предупреждение

Map<String, Object> myInput = (Map<String, Object>) myRequest.get();

Временное решение

Создайте новый объект карты без упоминания параметров, поскольку тип объекта, который содержится в списке, не проверен.

Шаг 1: Создайте новую временную карту

Map<?, ?> tempMap = (Map<?, ?>) myRequest.get();

Шаг 2: Создание основной карты

Map<String, Object> myInput=new HashMap<>(myInputObj.size());

Шаг 3: Итерация временной карты и установка значений в основную карту

 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }
Автор: Andy Размещён: 16.12.2016 02:23

2 плюса

36 Репутация автора

Решение, чтобы избежать непроверенного предупреждения:

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
Автор: ochakov Размещён: 28.08.2018 03:13

0 плюса

77582 Репутация автора

Что я сделал не так? Как мне решить проблему?

Вот :

Map<String,String> someMap = (Map<String,String>)getApplicationContext().getBean("someMap");

Вы используете устаревший метод, который мы обычно не хотим использовать, так как он возвращает Object:

Object getBean(String name) throws BeansException;

Метод для получения (для синглтона) / создания (для прототипа) компонента из фабрики компонентов:

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

Используя это как:

Map<String,String> someMap = app.getBean(Map.class,"someMap");

будет компилироваться, но все еще с предупреждением о непроверенном преобразовании, поскольку все Mapобъекты не обязательно являются Map<String, String>объектами.

Но <T> T getBean(String name, Class<T> requiredType) throws BeansException;этого недостаточно в универсальных классах bean, таких как универсальные коллекции, поскольку для этого требуется указать более одного класса в качестве параметра: тип коллекции и ее универсальный тип (типы).

В этом сценарии и в целом лучшим подходом является не непосредственное использование BeanFactoryметодов, а возможность структуры для внедрения компонента.

Объявление бина:

@Configuration
public class MyConfiguration{

    @Bean
    public Map<String, String> someMap() {
        Map<String, String> someMap = new HashMap();
        someMap.put("some_key", "some value");
        someMap.put("some_key_2", "some value");
        return someMap;
    }
}

Инъекция бобов:

@Autowired
@Qualifier("someMap")
Map<String, String> someMap;
Автор: davidxxx Размещён: 12.08.2019 02:02
Вопросы из категории :
32x32