Zabezpieczenie typu: odlew nieobrobiony

W moim pliku kontekstowym aplikacji wiosennej mam coś takiego:

<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>

W klasie java implementacja wygląda następująco:

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

W Eclipse, widzę Ostrzeżenie, które mówi:

Type safety: Unchecked cast from Object to HashMap

Co zrobiłem źle? Jak mogę rozwiązać problem?
Author: FabienB, 2008-11-04

9 answers

Po pierwsze, marnujesz pamięć z nowym wywołaniem tworzenia. Druga linia całkowicie pomija odniesienie do tej utworzonej hashmapy, czyniąc ją dostępną dla garbage collector. Więc nie rób tego, użyj:

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

Po Drugie, kompilator skarży się, że oddajesz obiekt HashMap bez sprawdzania, czy jest to HashMap. Ale nawet gdybyś miał zrobić:

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

Prawdopodobnie nadal otrzymałbyś to Ostrzeżenie. Problem w tym, że getBean zwraca Object, więc nie wiadomo, jaki jest typ. Konwersja do HashMap bezpośrednio nie spowodowałaby problemu w drugim przypadku (i być może nie byłoby ostrzeżenia w pierwszym przypadku, nie jestem pewien, jak pedantyczny jest kompilator Javy z ostrzeżeniami dla Javy 5). Jednak konwertujesz go na HashMap<String, String>.

Hashmapy są tak naprawdę mapami, które przyjmują obiekt jako klucz i mają obiekt jako wartość, HashMap<Object, Object> jeśli wolisz. W związku z tym nie ma gwarancji, że po otrzymaniu fasoli można ją przedstawić jako HashMap<String, String> ponieważ możesz mieć HashMap<Date, Calendar> ponieważ nie-ogólna reprezentacja, która jest zwracana, może mieć dowolne obiekty.

Jeśli kod zostanie skompilowany i możesz wykonać String value = map.get("thisString"); bez żadnych błędów, nie martw się tym ostrzeżeniem. Jeśli jednak mapa nie zawiera całkowicie kluczy łańcuchowych do wartości łańcuchowych, otrzymasz ClassCastException w czasie wykonywania, ponieważ generyki nie mogą tego zablokować.

 218
Author: MetroidFan2002,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-07 12:55:44

Problem polega na tym, że cast jest sprawdzaniem czasu pracy - ale ze względu na typ erasure, w czasie pracy nie ma żadnej różnicy między HashMap<String,String> i HashMap<Foo,Bar> dla innych Foo i Bar.

Użyj @SuppressWarnings("unchecked") i trzymaj nos. AHA, i kampania dla reified generics w Javie:)

 264
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 17:09:19

Jak wskazują powyższe wiadomości, listy nie można rozróżnić między A List<Object> i a List<String> lub List<Integer>.

Rozwiązałem ten Komunikat o błędzie dla podobnego problemu:

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

Z następującym:

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

Wyjaśnienie: pierwsza konwersja typu sprawdza, czy obiekt jest listą bez dbania o typy wewnątrz (ponieważ nie możemy zweryfikować typów wewnętrznych na poziomie listy). Druga konwersja jest teraz wymagana, ponieważ kompilator zna tylko listę zawiera jakieś przedmioty. To sprawdza typ każdego obiektu na liście, gdy jest dostępny.

 60
Author: Larry Landry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-02 10:05:02

Tylko Ostrzeżenie. Ostrzeżenie. Czasami ostrzeżenia są nieistotne, czasami nie. Są one używane, aby zwrócić twoją uwagę na coś, co kompilator myśli, że może być problemem, ale może nie być.

/Align = "left" / Jeśli jesteś absolutnie pewien, że Dana Obsada będzie bezpieczna, powinieneś rozważyć dodanie adnotacji w ten sposób (nie jestem pewien składni) tuż przed wierszem:
@SuppressWarnings (value="unchecked")
 21
Author: David M. Karr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 16:44:24

Otrzymujesz tę wiadomość, ponieważ getBean zwraca odniesienie do obiektu i przerzucasz je na właściwy typ. Java 1.5 daje ostrzeżenie. Taka jest natura używania Javy 1.5 lub lepszej z kodem, który działa w ten sposób. Wiosna ma wersję typesafe

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

Na jego liście todo.

 9
Author: David Nehme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-04 16:44:59

Jeśli naprawdę chcesz pozbyć się ostrzeżeń, możesz utworzyć klasę, która rozciąga się od klasy generycznej.

Na przykład, jeśli próbujesz użyć

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

Możesz utworzyć nową klasę w taki sposób

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

Wtedy gdy używasz

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

Kompilator wie, czym są (już nie ogólne) typy i nie będzie żadnego ostrzeżenia. Może to nie zawsze być idealne rozwiązanie, niektórzy mogą argumentować, że tego rodzaju klasy generyczne nie spełniają celu, ale nadal używasz tego samego kodu z klasy generic, po prostu deklarujesz w czasie kompilacji, jakiego typu chcesz użyć.

 5
Author: Rabbit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-13 15:55:31

Innym rozwiązaniem, jeśli często rzucasz ten sam obiekt i nie chcesz zaśmiecać kodu @SupressWarnings("unchecked"), byłoby stworzenie metody z adnotacją. W ten sposób centralizujesz obsadę i mam nadzieję, że zmniejszysz prawdopodobieństwo błędu.

@SuppressWarnings("unchecked")
public static List<String> getFooStrings(Map<String, List<String>> ctx) {
    return (List<String>) ctx.get("foos");
}
 1
Author: Jeremy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-20 19:25:17

Poniższy kod powoduje Typ Ostrzeżenia bezpieczeństwa

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

Obejście

Utwórz nowy obiekt mapy bez podawania parametrów, ponieważ typ obiektu przechowywanego na liście nie jest zweryfikowany.

Krok 1: Tworzenie nowej tymczasowej mapy

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

Krok 2: Instantiate the main Map

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

Krok 3: iteracja tymczasowej Mapy i ustawienie wartości do głównej mapy

 for(Map.Entry<?, ?> entry :myInputObj.entrySet()){
        myInput.put((String)entry.getKey(),entry.getValue()); 
    }
 0
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-16 14:23:25

Rozwiązanie, aby uniknąć niezaznaczonego Ostrzeżenia:

class MyMap extends HashMap<String, String> {};
someMap = (MyMap)getApplicationContext().getBean("someMap");
 0
Author: ochakov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-28 15:50:10