简单的回答是,在java中找不到泛型类型参数的运行时类型。我建议阅读java教程中有关类型擦除的一章以了解更多细节。 一个流行的解决办法是通过 Class 将类型参数的。
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
}
}
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 );
}
}
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();
}
}
你可以去上课 Bar.class 在foo类中选择 Type (来自伯特·布鲁尼的回答)并用 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> 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 __() {
}
}
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];
}
}
22条答案
按热度按时间fjnneemd1#
简单的回答是,在java中找不到泛型类型参数的运行时类型。我建议阅读java教程中有关类型擦除的一章以了解更多细节。
一个流行的解决办法是通过
Class
将类型参数的。zkure5ic2#
我一直在寻找一种方法来实现这一点,而不需要向类路径添加额外的依赖项。经过一些调查,我发现这是可能的,只要你有一个泛型超类型。这对我来说还可以,因为我正在使用一个带有泛型层超类型的dao层。如果这符合你的情况,那么这是最整洁的方法。
我遇到的大多数泛型用例都有某种泛型超类型。
List<T>
为了ArrayList<T>
或者GenericDAO<T>
为了DAO<T>
等等。纯java解决方案
在java中访问运行时泛型类型的文章解释了如何使用纯java来实现。
Spring解决方案
我的项目是使用spring,这是更好的,因为spring有一个方便实用的方法来查找类型。这对我来说是最好的方法,因为它看起来很整洁。我想如果你不使用spring,你可以编写自己的实用方法。
lzfw57am3#
但是有一个小漏洞:如果你定义你的
Foo
抽象类。这意味着您必须将类示例化为:(注意末尾的双大括号。)
现在您可以检索
T
运行时:但是请注意
mySuperclass
必须是类定义的超类,该类定义实际上定义了T
.它也不是很优雅,但你必须决定你是否喜欢
new Foo<MyType>(){}
或者new Foo<MyType>(MyType.class);
在你的代码里。例如:
然后:
mnowg1ta4#
标准方法/解决方法/解决方案是添加
class
对象,例如:nsc4cvqm5#
假设您有一个抽象的泛型超类:
还有第二个类用一个泛型条扩展foo,泛型条扩展t:
你可以去上课
Bar.class
在foo类中选择Type
(来自伯特·布鲁尼的回答)并用Class
示例:必须注意,此操作并不理想,因此最好缓存计算值,以避免对此进行多次计算。一个典型的用法是在泛型dao实现中。
最终实施:
当从其他函数中的foo类或bar类调用时,返回的值是bar.class。
6psbrbz96#
以下是一个可行的解决方案:
注意:只能用作超类
必须用类型化类进行扩展(
Child extends Generic<Integer>
)或
必须创建为匿名实现(
new Generic<Integer>() {};
)mrfwxfqh7#
我在一个抽象泛型类中遇到了这个问题。在这种特殊情况下,解决方案更简单:
后来在派生类上:
ej83mcc08#
你不能这样做,因为类型删除。另请参阅堆栈溢出问题java泛型-类型擦除-何时发生以及发生什么。
pobjuy329#
一个比其他人建议的类更好的方法是传入一个对象,这个对象可以执行您对该类所做的操作,例如,创建一个新示例。
xeufq47z10#
对于这个问题,我有一个(丑陋但有效的)解决方案,它不需要外部依赖项/库:
5sxhfpxr11#
有可能:
您需要两个来自hibernate generic dao/blob/master/dao/src/main/java/com/googlecode/genericdao/dao/daoutil.java的函数。
有关更多解释,请参见反射泛型。
9bfwbjaz12#
我假设,既然你有一个泛型类,你会有这样一个变量:
(此变量需要在构造函数处取一个值)
在这种情况下,您只需创建以下方法:
希望有帮助!
idfiyjo813#
我找到了一个通用而简单的方法。在我的类中,我创建了一个方法,该方法根据泛型类型在类定义中的位置返回泛型类型。假设类定义如下:
现在,让我们创建一些属性来持久化这些类型:
然后可以创建一个泛型方法,该方法基于泛型定义的索引返回类型:
最后,在构造函数中,只需调用方法并发送每个类型的索引。完整的代码应该如下所示:
jjhzyzn014#
如其他答案所述,使用
ParameterizedType
方法,您需要扩展类,但这似乎是额外的工作,使一个全新的类扩展它。。。因此,使类抽象化会迫使您对其进行扩展,从而满足子类化需求(使用lombok的@getter)。
现在不需要定义新类就可以扩展它(注意结尾的{}。。。扩展,但不要覆盖任何内容(除非您愿意)。
u2nhd7ah15#
这很直截了当。如果您需要来自同一班级: