Вопрос

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

<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

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

Это было полезно?

Решение

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

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

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

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

Вероятно, вы все равно получите это предупреждение. Проблема в том, что HashMap<String, String> возвращает HashMap<Object, Object>, поэтому неизвестно, что это за тип. Непосредственное преобразование его в HashMap<Date, Calendar> не вызовет проблемы во втором случае (и, возможно, в первом случае не будет предупреждения, я не уверен, насколько педантичен компилятор Java с предупреждениями для Java 5). Однако вы конвертируете его в String value = map.get("thisString");.

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

Если код компилируется, и вы можете выполнить <=> без ошибок, не беспокойтесь об этом предупреждении. Но если карта не полностью содержит строковые ключи для строковых значений, вы получите <=> во время выполнения, потому что в этом случае универсальные блоки не могут этого предотвратить.

Другие советы

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

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

Как видно из приведенных выше сообщений, список нельзя различить между List<Object> и 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 содержит какие-то объекты. Это проверяет тип каждого объекта в списке по мере его доступа.

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

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

@SuppressWarnings (value="unchecked")

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

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

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

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

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

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

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

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

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

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

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

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

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}

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

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()); 
    }

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

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top