2008-11-04 12 views
185

In meiner Feder Anwendungskontext Datei, ich habe so etwas wie:Typ Sicherheit: Guss Ungeprüfter

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

In Java-Klasse, sieht die Umsetzung wie:

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

In Eclipse sehe ich eine Warnung das sagt:

Typ Sicherheit: Ungeprüfter von Objekt werfen

Hashmap

Was habe ich falsch gemacht? Wie behebe ich das Problem?

+0

Verwandte/Betrogene: (http://stackoverflow.com/q/509076) – blahdiblah

+0

möglich doppelte [Wie kann ich nicht markiert Guss Warnungen sprechen?] von [Wie adressiere ich ungeprüfte Zauberwarnungen?] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings) –

+0

Ich kam mit einer Routine, um die Besetzung zu überprüfen zu parametrisieren HashMap, die die ungeprüfte Cast-Warnung beseitigt: [link] (http://stackoverflow.com/questions/509076/how-do-i-address-unchecked-cast-warnings/509230#509230) Ich würde das sagen ist die "richtige" Lösung, aber ob es wert ist oder nicht, könnte strittig sein. :) – skiphoppy

Antwort

211

Nun, zuerst verschwenden Sie Speicher mit dem neuen Erstellungsruf HashMap. Ihre zweite Zeile ignoriert den Verweis auf diese erstellte Hashmap vollständig und stellt sie dem Garbage Collector zur Verfügung. Also, tun Sie das nicht, zu verwenden:

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

Zweitens der Compiler beschwert sich, dass Sie das Objekt zu einem HashMap werfen, ohne zu überprüfen, ob es ein HashMap ist. Aber selbst wenn Sie es tun würden:

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

Sie würden wahrscheinlich immer noch diese Warnung erhalten. Das Problem ist, getBean gibt Object zurück, so dass es unbekannt ist, was der Typ ist. Wenn man es direkt in HashMap umwandelt, würde das Problem mit dem zweiten Fall nicht auftreten (und vielleicht würde es im ersten Fall keine Warnung geben, ich bin mir nicht sicher, wie pedantisch der Java-Compiler mit Warnungen für Java 5 ist). Sie konvertieren es jedoch in HashMap<String, String>.

HashMaps sind wirklich Karten, die ein Objekt als Schlüssel nehmen und ein Objekt als Wert haben, HashMap<Object, Object>, wenn Sie so wollen. Daher gibt es keine Garantie, dass, wenn Sie Ihre Bean erhalten, dass es als HashMap<String, String> dargestellt werden kann, weil Siehaben könnten, weil die nicht generische Darstellung, die zurückgegeben wird, beliebige Objekte haben kann.

Wenn der Code kompiliert und Sie String value = map.get("thisString"); ohne Fehler ausführen können, machen Sie sich keine Sorgen über diese Warnung. Wenn die Map jedoch nicht vollständig aus Zeichenfolgenschlüsseln besteht, um Zeichenfolgenwerte zu erhalten, erhalten Sie zur Laufzeit einen Wert ClassCastException, da die Generika dies in diesem Fall nicht blockieren können.

+10

Dies war vor einer Weile, aber ich war auf der Suche nach einer Antwort auf Typ Überprüfung eines Set vor einer Besetzung, und Sie können nicht in einer parametrisierten Generika instanceof. z.B. if (event.getTarget instanceof Set ) Sie können nur einen generischen Typ mit einem? und das wird die Cast-Warnung nicht entfernen. z.B. if (event.getTarget instanceof Set ) – garlicman

21

Eine Warnung ist nur das. Eine Warnung. Manchmal sind Warnungen irrelevant, manchmal nicht. Sie werden verwendet, um Ihre Aufmerksamkeit auf etwas zu lenken, von dem der Compiler glaubt, dass es ein Problem sein könnte, aber möglicherweise nicht.

Bei Güssen wird in diesem Fall immer eine Warnung ausgegeben. Wenn Sie absolut sicher sind, dass eine bestimmte Besetzung sicher sein wird, dann sollten Sie eine Anmerkung wie diese Zugabe (Ich bin die Syntax nicht sicher) kurz vor der Linie:

@SuppressWarnings (value="unchecked") 
+8

-1: Eine Warnung sollte niemals akzeptiert werden. Oder unterdrücken Sie diese Art von Warnungen oder beheben Sie sie. Es wird der Moment kommen, wo Sie viele Warnungen haben müssen und Sie werden das relevante nicht einmal sehen. – ezdazuzena

+5

Sie können Klassenausführungswarnungen nicht wirklich vermeiden, wenn Sie parametrisierte Generics, z. B. Map, umwandeln. Dies ist also die beste Antwort für die ursprüngliche Frage. – muttonUp

9

Sie erhalten diese Nachricht, weil getBean gibt eine Objektreferenz zurück und Sie werfen sie auf den richtigen Typ. Java 1.5 gibt Ihnen eine Warnung. Das ist die Natur der Verwendung von Java 1.5 oder besser mit Code, der so funktioniert. Spring hat die typsichere Version

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

auf seiner Todo-Liste.

248

Das Problem ist, dass eine Besetzung eine Laufzeitprüfung ist - aber aufgrund Typs Löschung, zur Laufzeit gibt es eigentlich keinen Unterschied zwischen einem HashMap<String,String> und HashMap<Foo,Bar> für andere Foo und Bar.

Verwenden Sie @SuppressWarnings("unchecked") und halten Sie die Nase. Oh, und die Kampagne für verdinglichten Generika in Java :)

+12

Ich werde Javas vereidigte Generika über untypisiertes NSMutableWhatever nehmen, was sich an jedem Tag der Woche wie ein Zehnjahressprung nach hinten anfühlt. Zumindest versucht Java. –

+11

Genau. Wenn Sie auf der Typprüfung bestehen, kann es nur mit HashMap erfolgen und das wird die Warnung nicht, da seine derselben entfernen, da nicht geben Sie die generischen Typen zu überprüfen. Es ist nicht das Ende der Welt, sondern ärgerlich, dass man erwischt wird, indem man entweder eine Warnung unterdrückt oder damit lebt. – garlicman

+1

@JonSkeet Was ist ein verdingter Generic? – SasQ

53

Da die Meldungen über angeben, die Liste kann nicht zwischen einem List<Object> und einem List<String> oder List<Integer> unterschieden werden.

ich diese Fehlermeldung für ein ähnliches Problem gelöst haben:

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

mit den folgenden:

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

Erläuterung: Der erste Typ-Konvertierung überprüft, ob das Objekt eine Liste ist, ohne sich um die Pflege die darin enthaltenen Typen (da wir die internen Typen auf Listenebene nicht überprüfen können). Die zweite Konvertierung ist jetzt erforderlich, da der Compiler nur weiß, dass die Liste eine Art von Objekten enthält. Dies überprüft den Typ jedes Objekts in der Liste beim Zugriff.

+1

Sie sind richtig mein Freund. Anstatt die Liste zu übertragen, wiederhole sie einfach und wirf jedes Element, die Warnung wird nicht angezeigt, großartig. –

+0

Dies entfernt die Warnung, aber ich bin noch nicht zuversichtlich: P – mumair

4

Wenn Sie die Warnungen wirklich loswerden wollen, können Sie eine Klasse erstellen, die von der generischen Klasse ausgeht.

Zum Beispiel, wenn Sie

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

Sie können eine neue Klasse erstellen, wie solche

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

Dann, wenn Sie

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

Der Compiler verwenden zu verwenden sind versucht DOES weiß, was die (nicht mehr generischen) Typen sind, und es wird keine Warnung geben. Dies mag nicht immer die perfekte Lösung sein, manche argumentieren, dass diese Art von Problemen den Zweck von generischen Klassen besiegt, aber Sie verwenden immer noch den gleichen Code aus der generischen Klasse, Sie deklarieren zur Kompilierungszeit nur, um welchen Typ es sich handelt Sie möchten verwenden.

1

Eine andere Lösung, wenn Sie finden, dass Sie das gleiche Objekt viel werfen und Sie Ihren Code nicht mit @SupressWarnings("unchecked") werfen wollen, wäre eine Methode mit der Anmerkung zu erstellen. Auf diese Weise zentrierst du die Besetzung und hoffst, dass dadurch die Möglichkeit für Fehler verringert wird.

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

Im Folgenden Code verursacht Typ Sicherheit Warnung

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

Umgehung

ein neues Map-Objekt erstellen, ohne die Parameter zu erwähnen, weil der Typ des Objekts gehalten innerhalb der Liste ist n ot verifiziert.

Schritt 1: Erstellen Sie eine neue temporäre Karte

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

Schritt 2: Instantiate der Hauptkarte

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

Schritt 3: Iterate die temporäre Karte und stellen Sie die Werte in die Hauptkarte

for(Map.Entry<?, ?> entry :myInputObj.entrySet()){ 
     myInput.put((String)entry.getKey(),entry.getValue()); 
    }