class Foo<T> {
final Class<T> typeParameterClass;
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}
9
这是一个有效的解决方案:
@SuppressWarnings("unchecked")
private 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 <> ");
}
}
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)
}
然后,您可以创建一个泛型方法,该方法根据泛型定义的索引返回类型:
/**
* 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];
}
最后,在构造函数中,只需调用方法并为每种类型发送索引 . 完整的代码应如下所示:
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];
}
}
1
这是可能的:
class Foo<T> {
Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}
您可以通过选择 Type (来自bert bruynooghe答案)并使用 Class 实例推断它来获取Foo类中的类 Bar.class :
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);
import java.lang.reflect.TypeVariable;
public static <T> Class<T> getGenericClass()
{
__<T> ins = new __<T>();
TypeVariable<?>[] cls = ins.getClass().getTypeParameters();
return (Class<T>)cls[0].getClass();
}
private final class __<T> // generic helper class which does only provide type information
{
private __()
{
}
}
82
public <T> T yourMethodSignature(Class<T> type) {
// get some object and check the type match the given type
Object result = ...
if (type.isAssignableFrom(result.getClass())) {
return (T)result;
} else {
// handle the error
}
}
@Getter
public abstract class ConfigurationDefinition<T> {
private Class<T> type;
...
public ConfigurationDefinition(...) {
this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
...
}
}
现在扩展它而不定义新类 . (注意最后的{} ...扩展,但不要覆盖任何东西 - 除非你想要) .
private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){};
private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){};
...
Class stringType = myConfigA.getType();
Class fileType = myConfigB.getType();
11
标准方法/变通方法/解决方案是将 class 对象添加到构造函数中,如:
public class Foo<T> {
private Class<T> type;
public Foo(Class<T> type) {
this.type = type;
}
public Class<T> getType() {
return type;
}
public T newInstance() {
return type.newInstance();
}
}
4
但是有一个小漏洞:如果你将 Foo 类定义为抽象 . 这意味着你必须将你的类实例化为:
Foo<MyType> myFoo = new Foo<MyType>(){};
(注意最后的双括号 . )
现在,您可以在运行时检索 T 的类型:
Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
但请注意, mySuperclass 必须是实际定义 T 的最终类型的类定义的超类 .
它也不是很优雅,但您必须在代码中决定是否更喜欢 new Foo<MyType>(){} 或 new Foo<MyType>(MyType.class); .
例如:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.NoSuchElementException;
/**
* Captures and silently ignores stack exceptions upon popping.
*/
public abstract class SilentStack<E> extends ArrayDeque<E> {
public E pop() {
try {
return super.pop();
}
catch( NoSuchElementException nsee ) {
return create();
}
}
public E create() {
try {
Type sooper = getClass().getGenericSuperclass();
Type t = ((ParameterizedType)sooper).getActualTypeArguments()[ 0 ];
return (E)(Class.forName( t.toString() ).newInstance());
}
catch( Exception e ) {
return null;
}
}
}
然后:
public class Main {
// Note the braces...
private Deque<String> stack = new SilentStack<String>(){};
public static void main( String args[] ) {
// Returns a new instance of String.
String s = stack.pop();
System.out.printf( "s = '%s'\n", s );
}
}
17 回答
简而言之,没有办法在Java中找出泛型类型参数的运行时类型 . 我建议阅读Java Tutorial中关于类型擦除的章节以获取更多详细信息 .
一种流行的解决方案是将类型参数的
Class
传递给泛型类型的构造函数,例如:这是一个有效的解决方案:
注意: Can be used only as superclass
Child extends Generic<Integer>
)OR
new Generic<Integer>() {};
)比其他人建议的类更好的路径是传入一个对象,该对象可以执行您对该类所做的操作,例如,创建一个新实例 .
由于类型擦除,你不能这样做 . 另请参阅Stack Overflow问题Java generics - type erasure - when and what happens .
我发现了一种通用且简单的方法 . 在我的课程中,我创建了一个方法,根据它在类定义中的位置返回泛型类型 . 我们假设一个类定义如下:
现在让我们创建一些属性来保存类型:
然后,您可以创建一个泛型方法,该方法根据泛型定义的索引返回类型:
最后,在构造函数中,只需调用方法并为每种类型发送索引 . 完整的代码应如下所示:
这是可能的:
您需要svn/trunk/dao/src/main/java/com/googlecode/genericdao/dao/ DAOUtil.java中的两个函数 .
有关更多说明,请参阅Reflecting generics .
想象一下,你有一个通用的抽象超类:
然后你有第二个类扩展了Foo,扩展了T:
您可以通过选择
Type
(来自bert bruynooghe答案)并使用Class
实例推断它来获取Foo类中的类Bar.class
:您必须注意此操作并不理想,因此最好缓存计算值以避免对此进行多次计算 . 其中一个典型用途是通用DAO实现 .
最终实施:
从其他函数或Bar类中的Foo类调用时,返回的值为Bar.class .
我在抽象泛型类中遇到了这个问题 . 在这种特殊情况下,解决方案更简单:
以及后来的派生类:
实际上,我想你的T类中有一个字段 . 如果没有T类字段,那么有一个泛型类型有什么意义呢?因此,您只需在该字段上执行instanceof即可 .
就我而言,我有一个
在我班上,我检查 class 类型是否为"Locality"
当然,这仅在可能的类的总数有限时才有效 .
我有一个(丑陋但有效)解决这个问题的方法,我最近用过:
我正在使用解决方法:
如果要扩展或实现使用泛型的任何类/接口,则可以获得父类/接口的通用类型,而无需修改任何现有的类/接口 .
可能有三种可能性,
Case 1 当您的类正在扩展使用泛型的类时
Case 2 当您的类正在实现使用Generics的接口时
Case 3 当您的界面正在扩展使用Generics的界面时
正如在其他答案中所解释的那样,要使用这个
ParameterizedType
方法,你需要扩展类,但这似乎是额外的工作来创建一个扩展它的全新类...因此,使类抽象它会强制您扩展它,从而满足子类化要求 . (使用lombok的@Getter) .
现在扩展它而不定义新类 . (注意最后的{} ...扩展,但不要覆盖任何东西 - 除非你想要) .
标准方法/变通方法/解决方案是将
class
对象添加到构造函数中,如:但是有一个小漏洞:如果你将
Foo
类定义为抽象 . 这意味着你必须将你的类实例化为:(注意最后的双括号 . )
现在,您可以在运行时检索
T
的类型:但请注意,
mySuperclass
必须是实际定义T
的最终类型的类定义的超类 .它也不是很优雅,但您必须在代码中决定是否更喜欢
new Foo<MyType>(){}
或new Foo<MyType>(MyType.class);
.例如:
然后:
我一直在寻找一种方法来自己做,而不需要在类路径上添加额外的依赖 . 经过一些调查后,我发现只要你有一个通用的超类型就可以.168189_ . 这对我来说没问题我正在使用具有通用图层超类型的DAO图层 . 如果这适合你的情况那么这是最好的方法恕我直言 .
我遇到的大多数泛型用例具有某种通用超类型,例如:
List<T>
代表ArrayList<T>
或GenericDAO<T>
代表DAO<T>
等纯Java解决方案
文章Accessing generic types at runtime in Java解释了如何使用纯Java来实现它 .
Spring解决方案
我的项目使用的是Spring,这更好,因为Spring有一个方便的实用方法来查找类型 . 这对我来说是最好的方法,因为它看起来最好 . 我想如果你没有使用Spring,你可以编写自己的实用方法 .