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


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

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

9 203

9 ответов:

Ну, во-первых, вы теряете память с новым 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>.

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

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

проблема в том, что приведение является проверкой времени выполнения - но из-за стирания типа во время выполнения фактически нет разницы между 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);

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

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

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

@SuppressWarnings (value="unchecked")

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

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

на список todo.

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

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

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: создать экземпляр main Карта

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");