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
?
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
?
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!
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 .
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() );
}
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];
}
}
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 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.
2 Stimmen
Versuchen Sie, diese Frage zu beantworten, ich denke, es ist ähnlich. stackoverflow.com/questions/1942644/
3 Stimmen
Mögliche Duplikate von Generischen Typ einer Klasse zur Laufzeit abrufen
1 Stimmen
Mögliche Duplikate von Instanziierung einer generischen Klasse in Java
2 Stimmen
import com.fasterxml.jackson.core.type.TypeReference;
new TypeReference<T>(){}
0 Stimmen
Ja, wie der obige Kommentar andeutet, habe ich das Problem durch die Bereitstellung von
new TypeReference<Foo<Bar>>() {}
als Parameter für meine deserialisierte Modelllesemethode.