Ich habe ähnliche Fragen gesehen, aber sie haben nicht viel geholfen.
Zum Beispiel habe ich diese generische Klasse:
public class ContainerTest<T>
{
public void doSomething()
{
//I want here to determinate the Class of the type argument (In this case String)
}
}
und eine andere Klasse, die diese Containerklasse verwendet
public class TestCase
{
private ContainerTest<String> containerTest;
public void someMethod()
{
containerTest.doSomething();
}
}
Ist es möglich, die Klasse des Typarguments in der Methode doSomething () zu bestimmen, ohne dass einen expliziten Typ Variable/Feld oder einen beliebigen Konstruktor in der ContainerTest-Klasse hat?
Update: Geändertes Format der ContainerTest-Klasse
Die einzige Möglichkeit ist, die Klasse in einer Instanzvariablen zu speichern und als Argument des Konstruktors anzufordern:
public class ContainerTest<T>
{
private Class<T> tClass;
public ContainerTest(Class<T> tClass) {
this.tCLass = tClass;
}
public void doSomething()
{
//access tClass here
}
}
Wenn Sie sich für die Reflection-Methode interessieren, habe ich in diesem großartigen Artikel eine Teillösung gefunden: http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Kurz gesagt, Sie können Java.lang.Class.getGenericSuperclass()
- und Java.lang.reflect.ParameterizedType.getActualTypeArguments()
-Methoden verwenden, müssen jedoch einige übergeordnete Superklassen unterteilen.
Der folgende Ausschnitt funktioniert für eine Klasse, die direkt die Oberklasse AbstractUserType
erweitert. Eine allgemeinere Lösung finden Sie im referenzierten Artikel.
import Java.lang.reflect.ParameterizedType;
public class AbstractUserType<T> {
public Class<T> returnedClass() {
ParameterizedType parameterizedType = (ParameterizedType) getClass()
.getGenericSuperclass();
@SuppressWarnings("unchecked")
Class<T> ret = (Class<T>) parameterizedType.getActualTypeArguments()[0];
return ret;
}
public static void main(String[] args) {
AbstractUserType<String> myVar = new AbstractUserType<String>() {};
System.err.println(myVar.returnedClass());
}
}
Es gibt keine "saubere" Methode, um das Argument "Generic Type" aus der Klasse zu erhalten. Ein allgemeines Muster besteht darin, die Klasse des "Generic Type" an den Konstruktor zu übergeben und sie als inneren Eigenschafts-Juste zu behalten, wie in der Java.util.EnumMap-Implementierung.
http://docs.Oracle.com/javase/1.5.0/docs/api/Java/util/EnumMap.htmlhttp://grepcode.com/file/repository.grepcode. de/Java/root/jdk/openjdk/6-b14/Java/util/EnumMap.Java
public class ContainerTest<T> {
Class<T> type;
T t;
public ContainerTest(Class<T> type) {
this.type = type;
}
public void setT(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void doSomething() {
//There you can use "type" property.
}
}
Nein. Dies ist aufgrund von Typlöschung (die Typparameter werden als Objekt + Typumwandlungen kompiliert) nicht möglich. Wenn Sie wirklich den Typ in der Laufzeit kennen/erzwingen müssen, können Sie einen Verweis auf ein Class
-Objekt speichern.
public class ContainerTest<T> {
private final Class<T> klass;
private final List<T> list = new ArrayList<T>();
ContainerTest(Class<T> klass) {
this.klass = klass;
}
Class<T> getElementClass() {
return klass;
}
void add(T t) {
//klass.cast forces a runtime cast operation
list.add(klass.cast(t));
}
}
Benutzen:
ContainerTest<String> c = new ContainerTest<>(String.class);
Um den Wert von T
zu erfahren, müssen Sie ihn in einer Typdefinition erfassen, indem Sie ContainerTest subclassing:
class MyStringClass extends ContainerTest<String> {}
Sie können dies auch mit einer anonymen Klasse tun, wenn Sie möchten:
ContainerTest<String> myStringClass = new ContainerTest<String>{}();
Um den Wert von T aufzulösen, können Sie TypeTools verwenden:
Class<?> stringType = TypeResolver.resolveRawArgument(ContainerTest.class, myStringClass.getClass());
assert stringType == String.class;
Wenn Sie so definieren können
public class ContainerTest<T>
{
public void doSomething(T clazz)
{
}
}
Dann ist es möglich
Es gibt is eine Möglichkeit, den Laufzeittyp des type-Parameters abzurufen, indem Sie mit Guavas TypeToken
diesen erfassen. Der Nachteil der Lösung besteht darin, dass Sie jedes Mal, wenn Sie eine Instanz von Container
benötigen, eine anonyme Unterklasse erstellen müssen.
class Container<T> {
TypeToken<T> tokenOfContainedType = new TypeToken<T>(getClass()) {};
public Type getContainedType() {
return tokenOfContainedType.getType();
}
}
class TestCase {
// note that containerTest is not a simple instance of Container,
// an anonymous subclass is created
private Container<String> containerTest = new Container<String>() {};
@Test
public void test() {
Assert.assertEquals(String.class, containerTest.getContainedType());
}
}
Der Schlüssel dieser Lösung wird im JavaDoc des Konstruktors von TypeToken
beschrieben, der im obigen Code verwendet wird:
Kunden erstellen eine leere anonyme Unterklasse. Dadurch wird der Typparameter in die Typhierarchie der anonymen Klasse eingebettet, sodass wir ihn trotz der Löschung zur Laufzeit wiederherstellen können.