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

В моем текстовом файле приложения 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

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

Ответ 1

Ну, во-первых, вы теряете память при новом вызове создания 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 во время выполнения, потому что генерики не могут заблокировать это в этом случае.

Ответ 2

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

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

Ответ 3

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

Ответ 4

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

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

@SuppressWarnings (value="unchecked")

Ответ 5

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

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

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

Ответ 6

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

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

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

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

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

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

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

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

Ответ 7

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

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

Ответ 8

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

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