I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using the code
我已经阅读了Java中带有反射贴子的泛型参数的Get类型,这让我想知道这是怎么可能的。我使用了有人发布和使用代码的解决方案。
List<Integer> l = new ArrayList<>();
Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
This, however does not work for me, resulting in
然而,这对我不起作用,导致了。
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
If I remove the class cast, the type of the actual argument is E
, which is the type definition from List interface.
如果我删除了类cast,那么实际参数的类型是E,这是List接口的类型定义。
My question is, therefore, am I doing something wrong here? This behaviour is something I would have expected anyway, since the types are supposed to be erased during compile time, correct?
我的问题是,我在这里做错了什么吗?这种行为是我应该预料到的,因为这些类型应该在编译时被删除,对吗?
3 个解决方案
#1
2
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
您使用的代码只在某些特定的情况下工作,在编译时,实际的类型参数是已知的(和存储的)。
For example if you did this:
例如,如果你这样做:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class
, because Integer
is "baked into" the IntegerList
.
在这种情况下,您所展示的代码实际上会返回整数。类,因为整数被“烤成”整数。
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken
:
一些库(ab)通过使用类型令牌来使用这个技巧。例如GSON类类型标记:
Represents a generic type
T
. You can use this class to get the generic type for a class. > For example, to get the generic type forCollection<Foo>
, you can use:表示一个泛型类型。您可以使用这个类来获得类的泛型类型。例如,为了获取集合
的泛型类型,您可以使用: Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>
.
这是有效的,因为这里创建的匿名类已经编译了它的类型参数为Collection
Note that this would not work (even if the TypeToken
class wouldn't prevent it by making its constructor protected):
请注意,这不会起作用(即使TypeToken类不会阻止它的构造函数保护它):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
#2
2
The javadoc will tell you what you are doing.
javadoc将告诉您正在做什么。
Class#getGenericSuperclass()
states
类# getGenericSuperclass()
Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class.
返回表示该类所表示的实体(类、接口、原始类型或void)的直接超类的类型。
If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. [...]
如果超类是参数化类型,则返回的类型对象必须准确地反映源代码中使用的实际类型参数。[…]
The direct superclass of ArrayList
is AbstractList
. The declaration is as such in the source code
ArrayList的直接超类是AbstractList。该声明在源代码中是这样的。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type
object returned by it, you will see
因此,如果打印返回的类型对象,您将看到。
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments()
which states
因此,参数化类型#getActualTypeArguments()是哪些状态。
Returns an array of Type objects representing the actual type arguments to this type.
返回表示该类型的实际类型参数的类型对象数组。
will return the Type
将返回类型
E
since E
is the actual type argument used in the ArrayList
class definition.
因为E是ArrayList类定义中使用的实际类型参数。
#3
1
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
您所描述的方法只在泛型类型由于继承而设置时才有效,因为在编译时就知道它:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
对于本例,您可以使用该方法,您将返回“String.class”。
If you are creating instances on the fly it won't work:
如果你在飞机上创建实例,它不会成功:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
一些常见的工作是,将实际的类作为参数传递,以供以后参考:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
用法:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object
. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you) (It's called Type Erasure)
实际上,您甚至不需要这种场景的泛型类型,因为Java会做同样的事情,就像处理“T”一样。唯一的优势是,您可以定义getter和Setter,并且不需要一直对对象进行类型转换。(因为Java正在为你这样做)(这被称为类型删除)
#1
2
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
您使用的代码只在某些特定的情况下工作,在编译时,实际的类型参数是已知的(和存储的)。
For example if you did this:
例如,如果你这样做:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class
, because Integer
is "baked into" the IntegerList
.
在这种情况下,您所展示的代码实际上会返回整数。类,因为整数被“烤成”整数。
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken
:
一些库(ab)通过使用类型令牌来使用这个技巧。例如GSON类类型标记:
Represents a generic type
T
. You can use this class to get the generic type for a class. > For example, to get the generic type forCollection<Foo>
, you can use:表示一个泛型类型。您可以使用这个类来获得类的泛型类型。例如,为了获取集合
的泛型类型,您可以使用: Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>
.
这是有效的,因为这里创建的匿名类已经编译了它的类型参数为Collection
Note that this would not work (even if the TypeToken
class wouldn't prevent it by making its constructor protected):
请注意,这不会起作用(即使TypeToken类不会阻止它的构造函数保护它):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
#2
2
The javadoc will tell you what you are doing.
javadoc将告诉您正在做什么。
Class#getGenericSuperclass()
states
类# getGenericSuperclass()
Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class.
返回表示该类所表示的实体(类、接口、原始类型或void)的直接超类的类型。
If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code. [...]
如果超类是参数化类型,则返回的类型对象必须准确地反映源代码中使用的实际类型参数。[…]
The direct superclass of ArrayList
is AbstractList
. The declaration is as such in the source code
ArrayList的直接超类是AbstractList。该声明在源代码中是这样的。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type
object returned by it, you will see
因此,如果打印返回的类型对象,您将看到。
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments()
which states
因此,参数化类型#getActualTypeArguments()是哪些状态。
Returns an array of Type objects representing the actual type arguments to this type.
返回表示该类型的实际类型参数的类型对象数组。
will return the Type
将返回类型
E
since E
is the actual type argument used in the ArrayList
class definition.
因为E是ArrayList类定义中使用的实际类型参数。
#3
1
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
您所描述的方法只在泛型类型由于继承而设置时才有效,因为在编译时就知道它:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
对于本例,您可以使用该方法,您将返回“String.class”。
If you are creating instances on the fly it won't work:
如果你在飞机上创建实例,它不会成功:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
一些常见的工作是,将实际的类作为参数传递,以供以后参考:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
用法:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object
. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you) (It's called Type Erasure)
实际上,您甚至不需要这种场景的泛型类型,因为Java会做同样的事情,就像处理“T”一样。唯一的优势是,您可以定义getter和Setter,并且不需要一直对对象进行类型转换。(因为Java正在为你这样做)(这被称为类型删除)