Ich bin auf ein seltsames Verhalten von Java gestoßen, das wie ein Fehler aussieht. Ist es? Durch das Umwandeln eines Objekts in einen generischen Typ (zB K
) wird keine ClassCastException
geworfen, auch wenn das Objekt keine Instanz von K
ist. Hier ist ein Beispiel:
Update : Danke an Cletus und Andrzej Doyle für Ihre hilfreichen Antworten. Da ich nur einen akzeptieren kann, akzeptiere ich Andrzej Doyles Antwort , weil sie mich zu einer Lösung geführt hat, die meiner Ansicht nach nicht zu schlecht ist. Ich denke, es ist eine etwas bessere Art, eine kleine Karte in einem Einzeiler zu initialisieren.
%Vor%Und dann nennst du es so:
%Vor%Wie es bei cetus heißt, bedeutet "Löschen", dass Sie dies zur Laufzeit nicht prüfen können (und dank Ihres Castings können Sie dies zur Kompilierzeit nicht überprüfen).
Bedenken Sie, dass Generika nur eine Kompilierzeitfunktion sind. Eine Sammlung Objekt hat keine generischen Parameter, nur die Referenzen , die Sie für dieses Objekt erstellen. Aus diesem Grund erhalten Sie eine Menge Warnungen über die "ungeprüfte Umwandlung", wenn Sie eine Sammlung von einem Raw-Typ oder gar Object
ablehnen müssen, da der Compiler keine Möglichkeit hat, zu überprüfen, ob das Objekt vom korrekten generischen Typ ist (da das Objekt selbst keinen generischen Typ hat).
Bedenke auch, was Casting bedeutet - es ist eine Art, dem Compiler zu sagen: "Ich weiß, dass du nicht unbedingt überprüfen kannst, ob die Typen übereinstimmen, aber vertraue mir , ich weiß, dass sie es tun" . Wenn du die Typprüfung überschreibst (falsch) und dann mit einem Typenkonflikt endet, wer wird dir die Schuld geben? ; -)
Es scheint, dass Ihr Problem auf dem Mangel an heterogenen generischen Datenstrukturen beruht. Ich würde vorschlagen, dass die Typ-Signatur Ihrer Methode eher wie private static<K,V> void addToMap(Map<K,V> map, List<Pair<K, V>> vals)
sein sollte, aber ich bin nicht davon überzeugt, dass Sie wirklich etwas bekommen. Eine Liste von Paaren ist im Grunde genommen eine Map. Daher wäre es genauso viel Arbeit, die typesafe vals
-Parameter zu erstellen, um die Methode aufzurufen, als nur die Map direkt zu füllen.
Wenn Sie wirklich, wirklich möchten, dass Ihre Klasse ungefähr so bleibt wie sie ist, aber runtime type-safety hinzufügt, wird Ihnen das Folgende vielleicht einige Ideen geben:
%Vor%Java Generics verwenden Type Erasure, was bedeutet, dass diese parametrisierten Typen zur Laufzeit nicht beibehalten werden, also ist dies völlig legal:
%Vor%, weil der kompilierte Bytecode mehr wie folgt aussieht:
%Vor% Java Generics sind einfach syntaktischer Zucker beim Casting Object
s.
Javas Generics werden mit "type dresden" erstellt, was bedeutet, dass der Code zur Laufzeit nicht weiß, dass Sie eine Map & lt; String, Integer & gt; - Es sieht nur eine Karte. Und da Sie den Inhalt in Objekte konvertieren (über die Parameterliste Ihrer addToMap-Funktion), sieht der Code zur Kompilierungszeit "richtig aus". Es versucht nicht, das Zeug beim Kompilieren auszuführen.
Wenn Sie die Typen zum Zeitpunkt der Kompilierung interessieren, rufen Sie sie nicht als Objekt auf. :) Machen Sie Ihre AddToMap-Funktion aussehen wie
%Vor%Wenn Sie mehrere Elemente in die Map einfügen möchten, sollten Sie eine Klasse wie map.Entry von java.util erstellen und Ihre Schlüssel / Wert-Paare in Instanzen dieser Klasse einbinden.
Dies ist eine ziemlich gute Erklärung dessen, was Generics in Java tun und was nicht: Ссылка
Es unterscheidet sich sehr stark von C #!
Ich glaube, Sie haben versucht, so etwas zu tun? Wo gibt es Kompilierzeit Sicherheit für die Paare, die Sie der Karte hinzufügen:
%Vor%Nach dem Kommentar bearbeiten:
Ahh, dann suchen Sie vielleicht nur nach dieser arkanen Syntax, um neue Mitarbeiter zu belästigen, die gerade auf Java umgestiegen sind.
%Vor%Java-Generics gelten nur während der Kompilierzeit und nicht zur Laufzeit. Das Problem ist die Art, wie Sie es implementiert haben, der Java-Compiler erhält keine Chance, die Typensicherheit zur Kompilierzeit zu gewährleisten.
Da ur K, V niemals sagen, dass sie irgendeine bestimmte Klasse erweitern, kann Java während der Kompilierzeit nicht wissen, dass es eine ganze Zahl sein sollte.
Wenn Sie Ihren Code wie folgt ändern
private statische void addToMap (Map, Objekt ... vals)
es wird Ihnen einen Fehler bei der Kompilierung geben