我的课程如下
abstract class GenericAnimal<T> {
public String doActionWithTheAnimal() {
return "Performing action with " + getGenericTypeClass();
}
private Class<?> getGenericTypeClass() {...} // how to get the Generic Type class?
}
class ZooAnimal extends GenericAnimal<Bear> {}
class Bear {}
class Test {
public static void main(String[] args) {
ZooAnimal animal = new ZooAnimal();
System.out.println(animal.doActionWithTheAnimal());
}
}
注意:很抱歉故意设计这个示例来适合我的用例。
我在网上找到了一个解决方案,其工作原理如下
private Class<?> getGenericTypeClass() {
return (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
我能想到的避免这段代码的另一种方法是要求 doActionWithTheAnimal() 方法的调用者自行传递类类型。我觉得不应该这样做,因为还有其他方法可以获取类类型而不询问代码的调用者/用户。
有人可以展示一种更简单/更干净的方法来获取泛型类型吗?
我可以看到另外两个选项。一种是将泛型类型作为构造函数参数传递:
abstract class GenericAnimal<T> {
private final Class<T> type;
GenericAnimal(Class<T> type) {
this.type = type
}
}
第二种是使用Guava的
TypeToken
来捕获类型:
abstract class GenericAnimal<T> {
TypeToken<T> type = new TypeToken<T>(getClass()) {};
}
new GenericAnimal<String>() {}.type // String
这是否是一种改进,取决于你。您自己的解决方案也是完全可行的。事实上,我想
TypeToken
在内部做了类似的事情。
有人可以展示一种更简单/更干净的方法来获取泛型类型吗?
不,没有比您概述的两种更好的方法了。
请注意,您描述的第二种方式(传递类)将您限制为
T
的非参数化值 - 例如,您无法创建 GenericAnimal<List<String>>
,因为不存在 List<String>.class
这样的东西。但是,您的第一种方法将允许这样的子类(除非您显式转换为 Class<T>
,这对于参数化 T
可能会失败)。
第一种方法并不是特别复杂或肮脏:它可以位于父类中,子类中不需要做任何其他事情就可以使用它。