Zso*_*rök 534
简而言之,没有办法在Java中找出泛型类型参数的运行时类型.我建议阅读Java Tutorial中关于类型擦除的章节以获取更多详细信息.
一种流行的解决方案是Class将type参数传递给泛型类型的构造函数,例如
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
}
}
Run Code Online (Sandbox Code Playgroud)
Ben*_*ley 212
我一直在寻找一种方法来自己做这个,而不需要在类路径上添加额外的依赖.经过一番调查,我发现,这是可能的,只要你有一个通用的超类型.这对我来说没问题,因为我正在使用带有通用图层超类型的DAO图层.如果这适合您的情况,那么这是最好的方法恕我直言.
我遇到的大多数泛型用例都有某种通用的超类型,例如List<T>for ArrayList<T>或GenericDAO<T>for DAO<T>等.
文章在Java中以运行时访问泛型类型说明了如何使用纯Java来实现它.
我的项目使用Spring,因为Spring有一个方便的实用方法来查找类型,因此更好.这对我来说是最好的方法,因为它看起来最好.我想如果你没有使用Spring,你可以编写自己的实用工具方法.
@SuppressWarnings("unchecked")
public GenericJpaDao() {
this.entityBeanType = ((Class) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]);
}
Run Code Online (Sandbox Code Playgroud)
ber*_*ghe 94
但是有一个小漏洞:如果你把你的Foo类定义为抽象.这意味着你必须将你的类实例化为:
Foo<MyType> myFoo = new Foo<MyType>(){};
Run Code Online (Sandbox Code Playgroud)
(注意最后的双括号.)
现在您可以检索T运行时的类型:
Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
Run Code Online (Sandbox Code Playgroud)
但请注意,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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后:
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 );
}
}
Run Code Online (Sandbox Code Playgroud)
And*_*s_D 36
标准方法/变通方法/解决方案是将一个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();
}
}
Run Code Online (Sandbox Code Playgroud)
dro*_*dpl 19
想象一下,你有一个通用的抽象超类:
public abstract class Foo<? extends T> {}
Run Code Online (Sandbox Code Playgroud)
然后你有第二个类扩展了Foo,扩展了T:
public class Second extends Foo<Bar> {}
Run Code Online (Sandbox Code Playgroud)
您可以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);
Run Code Online (Sandbox Code Playgroud)
您必须注意此操作并不理想,因此最好缓存计算值以避免对此进行多次计算.其中一个典型用途是通用DAO实现.
最终实施:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
从其他函数中的Foo类或Bar类调用时,返回的值为Bar.class.
Yar*_*bas 16
这是一个有效的解决方案:
@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 <> ");
}
}
Run Code Online (Sandbox Code Playgroud)
注意: 只能用作超类
Child extends Generic<Integer>)要么
new Generic<Integer>() {};) 我在抽象泛型类中遇到了这个问题.在这种特殊情况下,解决方案更简单:
abstract class Foo<T> {
abstract Class<T> getTClass();
//...
}
Run Code Online (Sandbox Code Playgroud)
以及后来的派生类:
class Bar extends Foo<Whatever> {
@Override
Class<T> getTClass() {
return Whatever.class;
}
}
Run Code Online (Sandbox Code Playgroud)
比其他人建议的类更好的路径是传入一个对象,该对象可以执行您对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>());
Run Code Online (Sandbox Code Playgroud)
我假设,既然你有一个泛型类,你就会有一个像这样的变量:
private T t;
Run Code Online (Sandbox Code Playgroud)
(这个变量需要在构造函数中取值)
在这种情况下,您可以简单地创建以下方法:
Class<T> getClassOfInstance()
{
return (Class<T>) t.getClass();
}
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你!
这是可能的:
class Foo<T> {
Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}
Run Code Online (Sandbox Code Playgroud)
有关更多解释,请参阅反映泛型。
我有一个(丑陋但有效)的解决方案,我最近使用过这个问题:
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 __()
{
}
}
Run Code Online (Sandbox Code Playgroud)