Wie kann ich das erreichen?
public class GenericClass<T>
{
public Type getMyType()
{
//How do I return the type of T?
}
}
Alles, was ich bisher versucht habe, gibt immer den Typ zurück Object
und nicht den spezifischen verwendeten Typ.
java
generics
reflection
Glenn
quelle
quelle
Antworten:
Wie bereits erwähnt, ist dies nur unter bestimmten Umständen durch Reflexion möglich.
Wenn Sie den Typ wirklich benötigen, ist dies das übliche (typsichere) Problemumgehungsmuster:
quelle
Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
public static <T> GenericClass<T> of(Class<T> type) {...}
und nenne es dann so :GenericClass<String> var = GenericClass.of(String.class)
. Ein bisschen schöner.Ich habe so etwas gesehen
im Beispiel für den Ruhezustand von GenericDataAccessObjects
quelle
class A implements Comparable<String>
der tatsächliche Typparameter istString
, aber es kann NICHT sagen, dass inSet<String> a = new TreeSet<String>()
der tatsächliche Typparameter istString
. Tatsächlich werden die Typparameterinformationen nach dem Kompilieren "gelöscht", wie in anderen Antworten erläutert.java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
für diese Antwort.Class-Mate
von den Jackson-Leuten erreicht werden. Ich habe hier eine Zusammenfassung geschrieben: gist.github.com/yunspace/930d4d40a787a1f6a7d1(Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()
, um zu den tatsächlichen Typargumenten zu gelangen.Generika werden zur Laufzeit nicht überprüft . Dies bedeutet, dass die Informationen zur Laufzeit nicht vorhanden sind.
Das Hinzufügen von Generika zu Java unter Wahrung der Abwärtskompatibilität war eine Tour de Force (Sie können das wegweisende Papier darüber lesen: Die Zukunft für die Vergangenheit sicher machen: der Java-Programmiersprache Generizität hinzufügen ).
Es gibt eine reiche Literatur zu diesem Thema, und einige Leute sind mit dem aktuellen Zustand unzufrieden , andere sagen, dass es tatsächlich ein Köder ist und es keinen wirklichen Bedarf dafür gibt. Sie können beide Links lesen, ich fand sie ziemlich interessant.
quelle
Benutze Guave.
Vor einiger Zeit, habe ich geschrieben , einige Voll fledge Beispiele einschließlich abstrakten Klassen und Unterklassen hier .
Hinweis: Dazu müssen Sie eine Unterklasse instanziieren von
GenericClass
damit der Typparameter korrekt gebunden werden kann. Andernfalls wird nur der Typ als zurückgegebenT
.quelle
java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized
. Also habe ich die Zeilenew TypeToken(getClass()) { }
auf geändertnew TypeToken<T>(getClass()) { }
. Jetzt läuft der Code einwandfrei, aber Type ist immer noch 'T'. Siehe dies: gist.github.com/m-manu/9cda9d8f9d53bead2035default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
GenericClass
, sollten Sie diese Klasseabstract
so gestalten , dass keine falsche Verwendung kompiliert wird.Sicher kannst du.
Java verwendet die Informationen zur Laufzeit aus Gründen der Abwärtskompatibilität nicht. Aber die Informationen sind tatsächlich vorhanden als Metadaten vorhanden und können über Reflektion abgerufen werden (sie werden jedoch immer noch nicht zur Typprüfung verwendet).
Aus der offiziellen API:
http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29
Allerdings , für Ihr Szenario würde ich nicht Reflexion verwenden. Ich persönlich bin eher geneigt, dies für Framework-Code zu verwenden. In Ihrem Fall würde ich den Typ einfach als Konstruktorparameter hinzufügen.
quelle
Java-Generika haben meistens Kompilierungszeit. Dies bedeutet, dass die Typinformationen zur Laufzeit verloren gehen.
wird zu so etwas kompiliert
Um die Typinformationen zur Laufzeit abzurufen, müssen Sie sie als Argument des ctor hinzufügen.
Beispiel:
quelle
private final Class<T> type;
Type t = //String[]
quelle
Ich habe folgenden Ansatz verwendet:
quelle
Ich glaube nicht, dass Sie das können. Java verwendet beim Kompilieren das Löschen von Typen, damit Ihr Code mit Anwendungen und Bibliotheken kompatibel ist, die vor Generika erstellt wurden.
Aus den Oracle-Dokumenten:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
quelle
Die in diesem Artikel von Ian Robertson beschriebene Technik funktioniert für mich.
Kurzes schnelles und schmutziges Beispiel:
quelle
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Ich denke, es gibt eine andere elegante Lösung.
Was Sie tun möchten, ist (sicher) den Typ des generischen Typparameters von der Concerete-Klasse an die Oberklasse zu "übergeben".
Wenn Sie sich erlauben, den Klassentyp als "Metadaten" für die Klasse zu betrachten, schlägt dies die Java-Methode zum Codieren von Metadaten zur Laufzeit vor: Anmerkungen.
Definieren Sie zunächst eine benutzerdefinierte Anmerkung in dieser Richtung:
Anschließend müssen Sie die Anmerkung Ihrer Unterklasse hinzufügen.
Dann können Sie diesen Code verwenden, um den Klassentyp in Ihrer Basisklasse abzurufen:
Einige Einschränkungen dieses Ansatzes sind:
PassedGenericType
) an ZWEI Stellen an und nicht an einer Stelle, die nicht trocken ist.quelle
Das ist meine Lösung:
quelle
Hier ist funktionierende Lösung !!!
HINWEISE: Kann nur als Oberklasse verwendet werden
1. Muss mit typed class (
Child extends Generic<Integer>
) erweitert werdenODER
2. Muss als anonyme Implementierung erstellt werden (
new Generic<Integer>() {};
)quelle
Das kannst du nicht. Wenn Sie der Klasse eine Mitgliedsvariable vom Typ T hinzufügen (Sie müssen sie nicht einmal initialisieren), können Sie damit den Typ wiederherstellen.
quelle
Hier ist eine Möglichkeit, die ich ein- oder zweimal verwenden musste:
Zusammen mit
quelle
Eine einfache Lösung für diese Kabine ist wie folgt
quelle
Um einige der Antworten hier zu vervollständigen, musste ich mithilfe der Rekursion den ParametrizedType von MyGenericClass abrufen, egal wie hoch die Hierarchie ist:
quelle
Hier ist mein Trick:
quelle
T
es sich um eine Typvariable handelt. In dem Fall, dassT
es sich um eine Typvariable handelt, erstellen die Varargs ein Array zum Löschen vonT
. Siehe z . B. http://ideone.com/DIPNwd .Nur für den Fall, dass Sie eine Variable mit dem generischen Typ speichern, können Sie dieses Problem leicht lösen, indem Sie eine getClassType-Methode wie folgt hinzufügen:
Ich verwende das bereitgestellte Klassenobjekt später, um zu überprüfen, ob es eine Instanz einer bestimmten Klasse ist, wie folgt:
quelle
value
ist , wennnull
? Zweitens, wasvalue
ist , wenn es sich um eine Unterklasse von handeltT
?Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();
kehrt zurück,Integer.class
wenn es zurückkehren sollNumber.class
. Es wäre richtiger, zurückzukehrenClass<? extends T>
.Integer.class
ist einClass<? extends Number>
aber keinClass<Number>
.Hier ist meine Lösung
Unabhängig davon, wie viele Ebenen Ihre Klassenhierarchie hat, funktioniert diese Lösung immer noch, zum Beispiel:
In diesem Fall ist getMyType () = java.lang.String
quelle
Exception in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.<init>(Main.java:43) at Main.main(Main.java:61)
quelle
Hier ist meine Lösung. Die Beispiele sollten es erklären. Die einzige Voraussetzung ist, dass eine Unterklasse den generischen Typ und kein Objekt festlegen muss.
quelle
Ich habe das gleiche gemacht wie @Moesio Above, aber in Kotlin könnte es so gemacht werden:
quelle
Es könnte für jemanden nützlich sein. Sie können java.lang.ref.WeakReference verwenden. diesen Weg:
quelle
WeakReference
? Bitte geben Sie eine Erklärung mit Ihrer Antwort, nicht nur einen Code.SomeClass<MyClass>
, können Sie diese Instanz instanziierenSomeClass
und aufrufengetType
und haben die LaufzeitMyClass
.WeakReference
? Was Sie gesagt haben, unterscheidet sich nicht von den meisten anderen Antworten.AtomicReference
,List
,Set
).Ich fand, dass dies eine einfache verständliche und leicht erklärbare Lösung ist
quelle
(T...t)
. (Deshalb funktioniert dieser Code nicht.)