В контекста на пролетното ми приложение имам нещо като:
<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 виждам предупреждение, което казва:
Безопасност на типа: Непроверено подаване от Object на HashMap
Какво съм направил погрешно? Как да разреша проблема?
Отговори:
218 за отговор № 1Първо, вие губите памет с новото HashMap
създаване на повикване. Втората ви линия напълно пренебрегва позоваването на тази създадена hashmap, което я прави достъпна за боклука. Така че, не го правете, използвайте:
private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
Второ, компилаторът се оплаква, че сте хвърлили обекта в a 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>
ако обичаш. По този начин, няма гаранция, че когато получите своя боб, той може да бъде представен като HashMap<String, String>
защото можеше да имаш HashMap<Date, Calendar>
защото негенеричното представяне, което се връща, може да има някакви обекти.
Ако кодът се компилира и можете да го изпълните String value = map.get("thisString");
без никакви грешки, не се притеснявайте за това предупреждение. Но ако картата не е изцяло от низови ключове за низови стойности, ще получите ClassCastException
по време на изпълнение, защото генеричните лекарства не могат да блокират това да се случи в този случай.
263 за отговор № 2
Проблемът е, че подаването е проверка по време на изпълнение - но поради вида на изтриването, по време на изпълнение всъщност няма разлика между HashMap<String,String>
и HashMap<Foo,Bar>
за всеки друг Foo
и Bar
.
употреба @SuppressWarnings("unchecked")
и задръж носа си. О, и кампания за утвърдени генерични продукти в Java :)
59 за отговор № 3
Както показват горните съобщения, списъкът не може да бъде различен между 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);
Обяснение: Първото преобразуване на типа проверява дали обектът е списък без да се грижи за типовете, които се съдържат в него (тъй като не можем да проверим вътрешните типове на ниво списък). Второто преобразуване сега е необходимо, защото компилаторът знае само, че Списъкът съдържа някакъв вид обекти. Така се проверява типа на всеки обект в списъка, тъй като той е достъпен.
22 за отговор № 4
Точно това е предупреждение. Предупреждение. Понякога предупрежденията са без значение, понякога те не са. Те са свикнали да привличат вниманието ви към нещо, което компилаторът смята за проблем, но може и да не е така.
В случай на хвърляне, той винаги ще дадепредупреждение в този случай. Ако сте абсолютно сигурни, че даден акцент ще бъде безопасен, тогава трябва да помислите за добавяне на бележка като тази (не съм сигурен за синтаксиса) точно преди реда:
@SuppressWarnings (value="unchecked")
9 за отговор № 5
Получавате това съобщение, защото getBeanвръща референция на обект и я препращате към правилния тип. Java 1.5 ви дава предупреждение. Това е естеството на използването на Java 1.5 или по-добре с код, който работи по този начин. Пролетта има typeafe версията
someMap=getApplicationContext().getBean<HashMap<String, String>>("someMap");
в списъка си със задачи.
5 за отговор № 6
Ако наистина искате да се отървете от предупрежденията, едно нещо, което можете да направите, е да създадете клас, който се простира от общия клас.
Например, ако се опитвате да използвате
private Map<String, String> someMap = new HashMap<String, String>();
Можете да създадете нов клас като такъв
public class StringMap extends HashMap<String, String>()
{
// Override constructors
}
Тогава, когато използвате
someMap = (StringMap) getApplicationContext().getBean("someMap");
Компилаторът не знае какво (не е повечегенерични), и няма да има предупреждение. Това може би не винаги е идеалното решение, някои може да се аргументират с този вид загуба на целта на общите класове, но вие все още използвате повторно целия код от общия клас, просто декларирате при компилация какъв тип искате да използвате.
1 за отговор № 7
Друго решение, ако откриете, че много често хвърляте един и същ обект и не искате да изхвърляте кода си с него @SupressWarnings("unchecked")
, би било да се създаде метод с анотацията. По този начин вие централизирате актьорите и се надяваме да намалите възможността за грешка.
@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
return (List<String>) ctx.get("foos");
}
0 за отговор № 8
Под кода причинява безопасност за тип Предупреждение
Map<String, Object> myInput = (Map<String, Object>) myRequest.get();
Временно решение
Създайте нов обект на Map без да споменавате параметрите, защото типът на обекта, който се съхранява в списъка, не е проверен.
Етап 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());
}