883 Stimmen

Wie erhalte ich eine Klasseninstanz des generischen Typs T?

Ich habe eine generische Klasse, Foo<T> . Bei einer Methode der Foo Ich möchte die Klasseninstanz des Typs T aber ich kann einfach nicht anrufen T.class .

Was ist der bevorzugte Weg, um das Problem zu umgehen? T.class ?

2 Stimmen

Versuchen Sie, diese Frage zu beantworten, ich denke, es ist ähnlich. stackoverflow.com/questions/1942644/

3 Stimmen

1 Stimmen

23voto

droidpl Punkte 5792

Stellen Sie sich vor, Sie haben eine abstrakte Oberklasse, die generisch ist:

public abstract class Foo<? extends T> {}

Und dann haben Sie eine zweite Klasse, die Foo mit einer generischen Bar erweitert, die T erweitert:

public class Second extends Foo<Bar> {}

Sie können die Klasse Bar.class in der Klasse Foo durch Auswahl der Option Type (aus der Antwort von bert bruynooghe) und deren Ableitung durch Class Instanz:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
//Parse it as String
String className = tType.toString().split(" ")[1];
Class clazz = Class.forName(className);

Es ist zu beachten, dass dieser Vorgang nicht ideal ist, so dass es eine gute Idee ist, den berechneten Wert zwischenzuspeichern, um mehrere Berechnungen zu vermeiden. Eine der typischen Verwendungen ist in der generischen DAO-Implementierung.

Die endgültige Umsetzung:

public abstract class Foo<T> {

    private Class<T> inferedClass;

    public Class<T> getGenericClass(){
        if(inferedClass == null){
            Type mySuperclass = getClass().getGenericSuperclass();
            Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
            String className = tType.toString().split(" ")[1];
            inferedClass = Class.forName(className);
        }
        return inferedClass;
    }
}

Der zurückgegebene Wert ist Bar.class, wenn er von der Klasse Foo in einer anderen Funktion oder von der Klasse Bar aufgerufen wird.

14voto

user1154664 Punkte 1372

Ich hatte dieses Problem in einer abstrakten generischen Klasse. In diesem speziellen Fall ist die Lösung einfacher:

abstract class Foo<T> {
    abstract Class<T> getTClass();
    //...
}

und später auf die abgeleitete Klasse:

class Bar extends Foo<Whatever> {
    @Override
    Class<T> getTClass() {
        return Whatever.class;
    }
}

13voto

unknown6656 Punkte 2457

Eigentlich ist es est möglich ( ohne externe Bibliotheken!)

Im Folgenden stelle ich meine (hässliche, aber effektive) Lösung für dieses Problem vor:

import java.lang.reflect.TypeVariable;

public static <T> Class<T> getGenericClass() {
    __<T> instance = new __<T>();
    TypeVariable<?>[] parameters = instance.getClass().getTypeParameters(); 

    return (Class<T>)parameters[0].getClass();
}

// Generic helper class which (only) provides type information. This avoids the
//   usage of a local variable of type T, which would have to be initialized.
private final class __<T> {
    private __() { }
}

12voto

Konrad Garus Punkte 51589

Das geht nicht, weil die Schrift gelöscht werden muss. Siehe auch Stack Overflow Frage Java Generics - Typenlöschung - wann und was passiert? .

10voto

Ricky Clarkson Punkte 2871

Ein besserer Weg als die von den anderen vorgeschlagene Klasse ist die Übergabe eines Objekts, das das tun kann, was Sie mit der Klasse getan hätten, z. B. eine neue Instanz erstellen.

interface Factory<T> {
  T apply();
}

<T> void List<T> make10(Factory<T> factory) {
  List<T> result = new ArrayList<T>();
  for (int a = 0; a < 10; a++)
    result.add(factory.apply());
  return result;
}

class FooFactory<T> implements Factory<Foo<T>> {
  public Foo<T> apply() {
    return new Foo<T>();
  }
}

List<Foo<Integer>> foos = make10(new FooFactory<Integer>());

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X