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

7voto

Pontios Punkte 2193

Ich gehe davon aus, dass Sie, da Sie eine generische Klasse haben, eine solche Variable haben würden:

private T t;

(diese Variable muss im Konstruktor einen Wert annehmen)

In diesem Fall können Sie einfach die folgende Methode erstellen:

Class<T> getClassOfInstance()
{
    return (Class<T>) t.getClass();
}

Hoffentlich hilft das!

6voto

Peter Tseng Punkte 12727

Das ist möglich:

class Foo<T> {
  Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}

Sie benötigen zwei Funktionen aus hibernate-generic-dao/blob/master/dao/src/main/java/com/googlecode/genericdao/dao/DAOUtil.java .

Für weitere Erklärungen, siehe Reflektierende Generika .

3voto

Gana Punkte 462

Das ist ziemlich einfach. Wenn Sie von innerhalb der gleichen Klasse benötigen:

Class clazz = this.getClass();
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
try {
        Class typeClass = Class.forName( parameterizedType.getActualTypeArguments()[0].getTypeName() );
        // You have the instance of type 'T' in typeClass variable

        System.out.println( "Class instance name: "+  typeClass.getName() );
    } catch (ClassNotFoundException e) {
        System.out.println( "ClassNotFound!! Something wrong! "+ e.getMessage() );
    }

3voto

Juan Urrego Punkte 313

Ich habe eine allgemeine und einfache Möglichkeit gefunden, dies zu tun. In meiner Klasse habe ich eine Methode erstellt, die den generischen Typ entsprechend seiner Position in der Klassendefinition zurückgibt. Gehen wir von einer Klassendefinition wie dieser aus:

public class MyClass<A, B, C> {

}

Lassen Sie uns nun einige Attribute erstellen, um die Typen zu erhalten:

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;

// Getters and setters (not necessary if you are going to use them internally)

    } 

Dann können Sie eine generische Methode erstellen, die den Typ auf der Grundlage des Index der generischen Definition zurückgibt:

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {
        // To make it use generics without supplying the class type
        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }

Im Konstruktor rufen Sie schließlich einfach die Methode auf und senden den Index für jeden Typ. Der vollständige Code sollte wie folgt aussehen:

public class MyClass<A, B, C> {

    private Class<A> aType;

    private Class<B> bType;

    private Class<C> cType;

    public MyClass() {
      this.aType = (Class<A>) getGenericClassType(0);
      this.bType = (Class<B>) getGenericClassType(1);
      this.cType = (Class<C>) getGenericClassType(2);
    }

   /**
     * Returns a {@link Type} object to identify generic types
     * @return type
     */
    private Type getGenericClassType(int index) {

        Type type = getClass().getGenericSuperclass();

        while (!(type instanceof ParameterizedType)) {
            if (type instanceof ParameterizedType) {
                type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
            } else {
                type = ((Class<?>) type).getGenericSuperclass();
            }
        }

        return ((ParameterizedType) type).getActualTypeArguments()[index];
    }
}

2voto

Marian Klühspies Punkte 13706

Ich habe ein Beispiel erstellt, das auf einer der beiden vielversprechendsten Lösungen zu dieser Frage basiert.

Das Ergebnis ist jedoch nicht so vielversprechend , zumindest für meinen Anwendungsfall.

Nur ein Ansatz funktioniert aber Sie brauchen eine Superklasse die die Methode und die generisch muss sein in der untergeordneten Klasse festgelegt y kann nicht dynamisch zugewiesen werden (was leider mein Anwendungsfall ist)

import org.junit.jupiter.api.Test;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class GenericTest {

    /**
     * only this will work!
     */
    @Test
    void testGetGenericTypeClassFromChildClassWithSpecifiedType() {
        TestClassWithSpecifiedType parent = new TestClassWithSpecifiedType();
        assertEquals(SomeGenericType.class, parent.getGenericTypeClass());
    }

    /**
     * won't work!
     */
    @Test
    void testGetGenericTypeClassFromChildClassWithUnspecifiedType() {
        TestClassWithUnspecifiedType<SomeGenericType> parent = new TestClassWithUnspecifiedType<>();
        assertThrows(IllegalStateException.class, parent::getGenericTypeClass);
    }

    /**
     * won't work
     */
    @Test
    void testGetGenericTypeClassWithUnspecifiedType() {
        SomeGenericTypedClass<SomeGenericType> parent = new SomeGenericTypedClass<>();
        assertThrows(IllegalStateException.class, parent::getGenericTypeClass);
    }

    /**
     * won't work
     * returns object instead!
     */
    @Test
    void testGetLoadedClassFromObject() {
        Foo<SomeGenericType> foo = new Foo<>();
        Class<?> barClass = foo.getBarClass();
        assertEquals(SomeGenericType.class, barClass);
    }

    /**
     * A class that has specified the type parameter
     */
    public static class TestClassWithSpecifiedType extends AbstractGenericTypedClass<SomeGenericType> {

    }

    /**
     * A class where the type parameter will be specified on demand
     *
     * @param <T>
     */
    public static class TestClassWithUnspecifiedType<T> extends AbstractGenericTypedClass<T> {

    }

    /**
     * An abstract class, because otherwise finding the parameter will not work
     */
    @SuppressWarnings("unchecked")
    public static abstract class AbstractGenericTypedClass<T> {
        @SuppressWarnings("unchecked")
        public Class<T> getGenericTypeClass() {
            try {
                String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
                Class<?> clazz = Class.forName(className);
                return (Class<T>) clazz;
            } catch (Exception e) {
                throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
            }
        }
    }

    /**
     * A typed class without abstract super class
     *
     * @param <T>
     */
    public static class SomeGenericTypedClass<T> {
        @SuppressWarnings("unchecked")
        public Class<T> getGenericTypeClass() {
            try {
                String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
                Class<?> clazz = Class.forName(className);
                return (Class<T>) clazz;
            } catch (Exception e) {
                throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
            }
        }
    }

    /**
     * Some generic type - won't work with primitives such as String, Integer, Double!
     */
    public static class SomeGenericType {

    }

    public static class Foo<T> {
        // The class:
        private final Class<?> barClass;

        public Foo() {
            try {
                // Im giving it [0] cuz Bar is the first TypeParam
                Type[] bounds = getClass().getTypeParameters()[0].getBounds();
                // Here, we get the class now:
                barClass = Class.forName(bounds[0].getTypeName());
            } catch (ClassNotFoundException e) {
                // will never happen!
                throw new Error("Something impossible happened!", e);
            }
        }

        public Class<?> getBarClass() {
            return barClass;
        }
    }
}

Ich verstehe nicht wirklich, warum dies so kompliziert sein muss, aber ich wette, dass es einige technische Beschränkungen für die dynamische Einstellung von Parametern geben muss.

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