Normalerweise habe ich gesehen, dass Leute das Klassenliteral wie folgt verwenden:
Class<Foo> cls = Foo.class;
Aber was ist, wenn der Typ generisch ist, zB List? Dies funktioniert gut, hat aber eine Warnung, da List parametrisiert werden sollte:
Class<List> cls = List.class
Warum also nicht ein hinzufügen <?>
? Nun, dies verursacht einen Typinkongruenzfehler:
Class<List<?>> cls = List.class
Ich dachte, so etwas würde funktionieren, aber das ist nur ein einfacher alter Syntaxfehler:
Class<List<Foo>> cls = List<Foo>.class
Wie kann ich Class<List<Foo>>
statisch eine erhalten, zB mit dem Klassenliteral?
Ich konnte verwenden , @SuppressWarnings("unchecked")
um die Warnungen durch die nicht-parametrisierte Verwendung von Liste im ersten Beispiel verursacht loszuwerden, Class<List> cls = List.class
aber ich möchte lieber nicht.
Irgendwelche Vorschläge?
List<Integer> list1 = new ArrayList<Integer>(); List<String> list2 = (List<String>)list1; list2.add("foo"); // perfectly legal
In Java ist dies nicht möglich. Es wird ein Kompilierungsfehler beim Typ-Mismatch angezeigt!List<String> list2 = (List<String>) (Object) list1;
Es gibt keine Klassenliterale für parametrisierte Typen, es gibt jedoch Typobjekte, die diese Typen korrekt definieren.
Siehe java.lang.reflect.ParameterizedType - http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html
Die Gson-Bibliothek von Google definiert eine TypeToken-Klasse, mit der einfach parametrisierte Typen generiert und json-Objekte mit komplexen parametrisierten Typen generisch benutzerfreundlich spezifiziert werden können. In Ihrem Beispiel würden Sie verwenden:
Ich wollte Links zu den Javadoc-Klassen TypeToken und Gson veröffentlichen, aber mit Stack Overflow kann ich nicht mehr als einen Link veröffentlichen, da ich ein neuer Benutzer bin. Sie können sie mithilfe der Google-Suche leicht finden
quelle
clzz = new TypeToken<E>(){}.getRawType();
später über ähnlich strukturierte Aufzählungen iterierenclzz.getEnumConstants()
und schließlich die Refektion verwenden, um Mitgliedsmethoden a laMethod method = clzz.getDeclaredMethod("getSomeFoo");
so viel Gewinn aufzurufen ! Danke!Sie können es mit einer Doppelbesetzung verwalten:
@SuppressWarnings("unchecked") Class<List<Foo>> cls = (Class<List<Foo>>)(Object)List.class
quelle
Object
in könnenClass
Sie wahrscheinlich den Overhead einer (sinnlosen) überprüften Laufzeitbesetzung sparen.Class
anstelle vonObject
, wie Sie vorschlagen, scheint sinnvoller, aber es entfernt nicht die Notwendigkeit der@SuppressWarnings("unchecked")
Anmerkung, es fügt sogar eine neue Warnung hinzu:Class is a raw type. References to generic type Class<T> should be parameterized
Class<?>
:(Class<List<Foo>>)(Class<?>)List.class
unchecked
Warnung erhielt. Diese Antwort ändert / verbessert nichts davon. OP sagt sogar in seiner Frage, dass er nicht verwenden willSuppressWarnings
...Um die Antwort von cletus zu erläutern, werden zur Laufzeit alle Datensätze der generischen Typen entfernt. Generika werden nur im Compiler verarbeitet und dienen der zusätzlichen Typensicherheit. Sie sind wirklich nur eine Abkürzung, mit der der Compiler Typecasts an den entsprechenden Stellen einfügen kann. Zuvor mussten Sie beispielsweise Folgendes tun:
wird
Auf diese Weise kann der Compiler Ihren Code zur Kompilierungszeit überprüfen, zur Laufzeit sieht er jedoch immer noch wie das erste Beispiel aus.
quelle
Die Java Generics-FAQ und damit auch die Antwort von cletus klingen so, als hätte es keinen Sinn, sie zu
Class<List<T>>
haben. Das eigentliche Problem ist jedoch, dass dies äußerst gefährlich ist:Das
cast()
lässt es so aussehen, als ob es sicher ist, aber in Wirklichkeit ist es überhaupt nicht sicher.Obwohl ich nicht verstehe, wo es nicht geben kann
List<?>.class
=,Class<List<?>>
da dies ziemlich hilfreich wäre, wenn Sie eine Methode haben, die den Typ basierend auf dem generischen Typ einesClass
Arguments bestimmt.Es
getClass()
gibt JDK-6184881 , das die Umstellung auf die Verwendung von Platzhaltern anfordert. Es sieht jedoch nicht so aus, als würde diese Änderung (sehr bald) durchgeführt, da sie nicht mit dem vorherigen Code kompatibel ist (siehe diesen Kommentar ).quelle
Wie wir alle wissen, wird es gelöscht. Unter bestimmten Umständen kann jedoch bekannt sein, dass der Typ in der Klassenhierarchie explizit erwähnt wird:
Und jetzt können Sie Dinge tun wie:
Mehr Infos hier . Aber auch hier ist es fast unmöglich, Folgendes abzurufen:
wo es gelöscht wird.
quelle
GenericEntity
undGenericType
.Aufgrund der Tatsache, dass Klassenliterale keine allgemeinen Typinformationen enthalten, sollten Sie davon ausgehen, dass es unmöglich sein wird, alle Warnungen zu entfernen. In gewisser Weise entspricht die Verwendung
Class<Something>
der Verwendung einer Sammlung ohne Angabe des generischen Typs. Das Beste, was ich herausbringen konnte, war:quelle
Sie können eine Hilfsmethode verwenden, um die
@SuppressWarnings("unchecked")
gesamte Klasse zu entfernen .Dann könntest du schreiben
Andere Anwendungsbeispiele sind
Da es jedoch selten wirklich nützlich ist und die Verwendung der Methode die Typprüfung des Compilers zunichte macht, würde ich nicht empfehlen, es an einem Ort zu implementieren, an dem es öffentlich zugänglich ist.
quelle