wake-up-neo.com

So erhalten Sie die Klasse der Typvariablen in Java Generics

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

18
ZeDonDino

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
    }
}
13
Didier L

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());
    }

}
9
dedek

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.
    }
}
5
RenaudBlue

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);
2
Javier

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;
1
Jonathan

Wenn Sie so definieren können

public class ContainerTest<T>
{

    public void doSomething(T clazz)
    {

    }
}

Dann ist es möglich

0
Arsen Alexanyan

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.

0
zagyi