Java 如何获得泛型类型 T 的类实例?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3437897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I get a class instance of generic type T?
提问by robinmag
I have a generics class, Foo<T>
. In a method of Foo
, I want to get the class instance of type T
, but I just can't call T.class
.
我有一个泛型类,Foo<T>
. 在 的方法中Foo
,我想获取 type 的类实例T
,但我无法调用T.class
.
What is the preferred way to get around it using T.class
?
使用 解决它的首选方法是什么T.class
?
采纳答案by Zsolt T?r?k
The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. I suggest reading the chapter about type erasure in the Java Tutorialfor more details.
简短的回答是,无法在 Java 中找出泛型类型参数的运行时类型。我建议阅读Java 教程中有关类型擦除的章节以获取更多详细信息。
A popular solution to this is to pass the Class
of the type parameter into the constructor of the generic type, e.g.
一个流行的解决方案是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
}
}
回答by Konrad Garus
You can't do it because of type erasure. See also Stack Overflow question Java generics - type erasure - when and what happens.
由于类型擦除,您不能这样做。另请参阅堆栈溢出问题Java 泛型 - 类型擦除 - 发生的时间和情况。
回答by Andreas Dolk
A standard approach/workaround/solution is to add a class
object to the constructor(s), like:
标准方法/解决方法/解决方案是向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();
}
}
回答by Ricky Clarkson
A better route than the Class the others suggested is to pass in an object that can do what you would have done with the Class, e.g., create a new instance.
比其他人建议的 Class 更好的方法是传入一个对象,该对象可以执行您对 Class 执行的操作,例如,创建一个新实例。
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>());
回答by bert bruynooghe
There is a small loophole however: if you define your Foo
class as abstract.
That would mean you have to instantiate you class as:
但是有一个小漏洞:如果您将Foo
类定义为抽象类。这意味着您必须将类实例化为:
Foo<MyType> myFoo = new Foo<MyType>(){};
(Note the double braces at the end.)
(注意末尾的双括号。)
Now you can retrieve the type of T
at runtime:
现在您可以T
在运行时检索类型:
Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
Note however that mySuperclass
has to be the superclass of the class definition actually defining the final type for T
.
但是请注意,mySuperclass
它必须是实际定义最终类型的类定义的超类T
。
It is also not very elegant, but you have to decide whether you prefer new Foo<MyType>(){}
or new Foo<MyType>(MyType.class);
in your code.
它也不是很优雅,但你必须决定是你喜欢new Foo<MyType>(){}
还是new Foo<MyType>(MyType.class);
在你的代码中。
For example:
例如:
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;
}
}
}
Then:
然后:
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 );
}
}
回答by Christine
Actually, I suppose you have a field in your class of type T. If there's no field of type T, what's the point of having a generic Type? So, you can simply do an instanceof on that field.
实际上,我假设您的类中有一个 T 类型的字段。如果没有 T 类型的字段,那么拥有泛型 Type 有什么意义?所以,你可以简单地在那个字段上做一个 instanceof 。
In my case, I have a
就我而言,我有一个
List<T> items;在我的班级中,我检查班级类型是否为“Locality”
if (items.get(0) instanceof Locality) ...
Of course, this only works if the total number of possible classes is limited.
当然,这仅在可能的类总数有限的情况下才有效。
回答by Ben Thurley
I was looking for a way to do this myself without adding an extra dependency to the classpath. After some investigation I found that it ispossible as long as you have a generic supertype. This was OK for me as I was working with a DAOlayer with a generic layer supertype. If this fits your scenario then it's the neatest approach IMHO.
我正在寻找一种方法来自己完成此操作,而无需向类路径添加额外的依赖项。经过一番调查,我发现,这是可能的,只要你有一个通用的超类型。这对我来说没问题,因为我正在使用具有通用层超类型的DAO层。如果这适合您的情况,那么恕我直言,这是最简洁的方法。
Most generics use cases I've come across have some kind of generic supertype e.g. List<T>
for ArrayList<T>
or GenericDAO<T>
for DAO<T>
, etc.
我遇到的大多数泛型用例都有某种泛型超类型,例如List<T>
forArrayList<T>
或GenericDAO<T>
forDAO<T>
等。
Pure Java solution
纯Java解决方案
The article Accessing generic types at runtime in Javaexplains how you can do it using pure Java.
这篇文章中的Java运行时访问泛型类型介绍如何使用纯Java做到这一点。
@SuppressWarnings("unchecked")
public GenericJpaDao() {
this.entityBeanType = ((Class) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]);
}
Spring solution
弹簧解决方案
My project was using Springwhich is even better as Spring has a handy utility method for finding the type. This is the best approach for me as it looks neatest. I guess if you weren't using Spring you could write your own utility method.
我的项目使用的是Spring,它更好,因为 Spring 有一个方便的实用方法来查找类型。这对我来说是最好的方法,因为它看起来最整洁。我想如果您不使用 Spring,您可以编写自己的实用程序方法。
import org.springframework.core.GenericTypeResolver;
public abstract class AbstractHibernateDao<T extends DomainObject> implements DataAccessObject<T>
{
@Autowired
private SessionFactory sessionFactory;
private final Class<T> genericType;
private final String RECORD_COUNT_HQL;
private final String FIND_ALL_HQL;
@SuppressWarnings("unchecked")
public AbstractHibernateDao()
{
this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractHibernateDao.class);
this.RECORD_COUNT_HQL = "select count(*) from " + this.genericType.getName();
this.FIND_ALL_HQL = "from " + this.genericType.getName() + " t ";
}
回答by user1154664
I had this problem in an abstract generic class. In this particular case, the solution is simpler:
我在抽象泛型类中遇到了这个问题。在这种特殊情况下,解决方案更简单:
abstract class Foo<T> {
abstract Class<T> getTClass();
//...
}
and later on the derived class:
后来在派生类上:
class Bar extends Foo<Whatever> {
@Override
Class<T> getTClass() {
return Whatever.class;
}
}
回答by Peter Tseng
It's possible:
这是可能的:
class Foo<T> {
Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}
You need two functions from hibernate-generic-dao/blob/master/dao/src/main/java/com/googlecode/genericdao/dao/DAOUtil.java.
For more explanations, see Reflecting generics.
有关更多解释,请参阅反映泛型。
回答by droidpl
Imagine you have an abstract superclass that is generic:
假设您有一个泛型的抽象超类:
public abstract class Foo<? extends T> {}
And then you have a second class that extends Foo with a generic Bar that extends T:
然后你有第二个类,它使用一个扩展 T 的泛型 Bar 扩展 Foo:
public class Second extends Foo<Bar> {}
You can get the class Bar.class
in the Foo class by selecting the Type
(from bert bruynooghe answer) and infering it using Class
instance:
您可以Bar.class
通过选择Type
(来自 bert bruynooghe 答案)并使用Class
实例推断它来获取Foo类中的类:
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);
You have to note this operation is not ideal, so it is a good idea to cache the computed value to avoid multiple calculations on this. One of the typical uses is in generic DAO implementation.
您必须注意此操作并不理想,因此最好缓存计算值以避免对此进行多次计算。典型用途之一是在通用 DAO 实现中。
The final implementation:
最后的实现:
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;
}
}
The value returned is Bar.class when invoked from Foo class in other function or from Bar class.
从其他函数中的 Foo 类或 Bar 类调用时,返回的值为 Bar.class。