泛型 Java - 获取泛型的泛型类型
Generics Java - Get type of generics of generics
我怎样才能得到这个 class 的类型?
对于上下文,我正在使用 modelMapper 并且我需要 class 类型 T 以从 S 转换为 T。
@Component
public class A<T, S> {
private Class<T> tType;
private Class<S> sType;
@SuppressWarnings("unchecked")
public A() {
this.tType = (Class<T>) // some method to take the type
this.sType = (Class<S>) // some method to take the type
}
public T toModel(S regras) {
return modelMapper.map(regras, tType);
}
上下文:
public class B{
@Autowired
private A<SomeClassX, SomeClassY> var;
// Some code
我已经尝试了 N 种方式,我把“// some method to take the type”放在了那里,但没有任何效果。例如:
@SuppressWarnings("unchecked")
public A() {
this.tType = (Class<T>) getGenericClassType(0);
this.sType = (Class<S>) getGenericClassType(1);
}
private Type getGenericClassType(int index) {
Type type = getClass().getGenericSuperclass();
while(!(type instanceof ParameterizedType)) {
if (type == null) {
return null;
}
if (type instanceof ParameterizedType) {
type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
} else {
type = ((Class<?>) type).getGenericSuperclass();
}
}
return ((ParameterizedType) type).getActualTypeArguments()[index];
}
或
@SuppressWarnings("unchecked")
public A() {
this.tType = (Class<T>) GenericTypeResolver.resolveTypeArguments(getClass(), GenericConverter.class)[0];
this.sType = (Class<S>) GenericTypeResolver.resolveTypeArguments(getClass(), GenericConverter.class)[1];
}
你不能。泛型是编译器想象力的产物:编译器使用它们来生成错误并注入强制转换,然后将其全部删除。它不在 class 文件中,因此在运行时不可用,因此,'what is my T actually' 的概念是 不可能的 。
有解决方法:
java.lang.Class
您当然可以将 j.l.Class 实例传递给构造函数。您的代码段使用名称 'A' 和 'B' 非常不幸,因为 single-caps 通常用于类型变量,所以我将其命名为 MyCompA 和 MyCombB。
类似于:
public class MyCompA<S, T> {
private final Class<S> sourceType;
private final Class<T> targetType;
public MyCompA(Class<S> sourceType, Class<T> targetType) {
this.sourceType = sourceType;
this.targetType = targetType;
}
public T toModel(S regras) {
return modelMapper.map(regras, targetType);
}
}
尽管如此,听起来您实际上并不需要 sourceType
任何东西,所以您最好不要使用它。
这个策略的问题是two-fold:
j.l.Class
实例可以表示泛型无法表示的东西。具体来说,原语:int
,原语,有一个代表它的j.l.Class
实例;您可以使用表达式 int.class
获取它。 int
不是有效的泛型(无论如何,可能在未来的 java 版本中):Class<int>
不起作用,List<int>
.[=71 也不起作用=]
- 一个
j.l.Class
实例只能代表基本类型——即被擦除的。 List<String>
不能 表示为 j.l.Class
实例。这意味着 S 和 T 类型 本身不能有泛型 这通常是一个破坏因素 - 你可能希望能够将某些东西映射到 List<String>
.
超类型代币
一种出路是 STT。他们看起来很时髦。制作它们:
TypeToken<List<String>> = new TypeToken<>() {};
注意那里奇怪的尾随 {}
。这创建了一个匿名 class 和 classes do 携带泛型信息,这些信息在编译后仍然存在,因此可以通过反射访问进行查询。运行时系统不会对它做任何事情 - 就 JVM 而言,它是注释(JVM 不知道什么是泛型,也不会将它们用于任何事情。它在 class 文件中是为了方便仅 javac
....但我们可以通过思考阅读它,所以就是这样)。
public abstract class TypeToken<T> {
public Type getType() {
Type t = getClass().getGenericSuperclass();
if (!(t instanceof ParameterizedType pt)) throw new IllegalStateException("Incorrect use of TypeToken: " + t);
Type[] typeArgs = pt.getActualTypeArguments();
if (typeArgs.length == 1) return typeArgs;
throw new IllegalStateException("Incorrect use of TypeToken: " + t);
}
我已经向您展示了如何创建这些实例。如果需要,您可以在构造函数中包含对 getType()
的调用(并且您可能希望缓存 return 值;它不能更改并且反射可能有点昂贵),因为那样当您制作无效的类型标记时,您会得到异常(例如:new TypeToken() {}
- 这是原始用法,当然在这里不起作用,重点是捕获 <>
中的内容)。
API麻烦!
您的 modelMapper.map
方法显然需要 Class<>
类型的值。如前所述,那些 不能 代表泛型,所以这个映射器只能映射到基本 typeargs-less 类型。在这种情况下,STT 完全矫枉过正,您只需要传递 class 个实例的简单解决方案。
我怎样才能得到这个 class 的类型? 对于上下文,我正在使用 modelMapper 并且我需要 class 类型 T 以从 S 转换为 T。
@Component
public class A<T, S> {
private Class<T> tType;
private Class<S> sType;
@SuppressWarnings("unchecked")
public A() {
this.tType = (Class<T>) // some method to take the type
this.sType = (Class<S>) // some method to take the type
}
public T toModel(S regras) {
return modelMapper.map(regras, tType);
}
上下文:
public class B{
@Autowired
private A<SomeClassX, SomeClassY> var;
// Some code
我已经尝试了 N 种方式,我把“// some method to take the type”放在了那里,但没有任何效果。例如:
@SuppressWarnings("unchecked")
public A() {
this.tType = (Class<T>) getGenericClassType(0);
this.sType = (Class<S>) getGenericClassType(1);
}
private Type getGenericClassType(int index) {
Type type = getClass().getGenericSuperclass();
while(!(type instanceof ParameterizedType)) {
if (type == null) {
return null;
}
if (type instanceof ParameterizedType) {
type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
} else {
type = ((Class<?>) type).getGenericSuperclass();
}
}
return ((ParameterizedType) type).getActualTypeArguments()[index];
}
或
@SuppressWarnings("unchecked")
public A() {
this.tType = (Class<T>) GenericTypeResolver.resolveTypeArguments(getClass(), GenericConverter.class)[0];
this.sType = (Class<S>) GenericTypeResolver.resolveTypeArguments(getClass(), GenericConverter.class)[1];
}
你不能。泛型是编译器想象力的产物:编译器使用它们来生成错误并注入强制转换,然后将其全部删除。它不在 class 文件中,因此在运行时不可用,因此,'what is my T actually' 的概念是 不可能的 。
有解决方法:
java.lang.Class
您当然可以将 j.l.Class 实例传递给构造函数。您的代码段使用名称 'A' 和 'B' 非常不幸,因为 single-caps 通常用于类型变量,所以我将其命名为 MyCompA 和 MyCombB。
类似于:
public class MyCompA<S, T> {
private final Class<S> sourceType;
private final Class<T> targetType;
public MyCompA(Class<S> sourceType, Class<T> targetType) {
this.sourceType = sourceType;
this.targetType = targetType;
}
public T toModel(S regras) {
return modelMapper.map(regras, targetType);
}
}
尽管如此,听起来您实际上并不需要 sourceType
任何东西,所以您最好不要使用它。
这个策略的问题是two-fold:
j.l.Class
实例可以表示泛型无法表示的东西。具体来说,原语:int
,原语,有一个代表它的j.l.Class
实例;您可以使用表达式int.class
获取它。int
不是有效的泛型(无论如何,可能在未来的 java 版本中):Class<int>
不起作用,List<int>
.[=71 也不起作用=]- 一个
j.l.Class
实例只能代表基本类型——即被擦除的。List<String>
不能 表示为j.l.Class
实例。这意味着 S 和 T 类型 本身不能有泛型 这通常是一个破坏因素 - 你可能希望能够将某些东西映射到List<String>
.
超类型代币
一种出路是 STT。他们看起来很时髦。制作它们:
TypeToken<List<String>> = new TypeToken<>() {};
注意那里奇怪的尾随 {}
。这创建了一个匿名 class 和 classes do 携带泛型信息,这些信息在编译后仍然存在,因此可以通过反射访问进行查询。运行时系统不会对它做任何事情 - 就 JVM 而言,它是注释(JVM 不知道什么是泛型,也不会将它们用于任何事情。它在 class 文件中是为了方便仅 javac
....但我们可以通过思考阅读它,所以就是这样)。
public abstract class TypeToken<T> {
public Type getType() {
Type t = getClass().getGenericSuperclass();
if (!(t instanceof ParameterizedType pt)) throw new IllegalStateException("Incorrect use of TypeToken: " + t);
Type[] typeArgs = pt.getActualTypeArguments();
if (typeArgs.length == 1) return typeArgs;
throw new IllegalStateException("Incorrect use of TypeToken: " + t);
}
我已经向您展示了如何创建这些实例。如果需要,您可以在构造函数中包含对 getType()
的调用(并且您可能希望缓存 return 值;它不能更改并且反射可能有点昂贵),因为那样当您制作无效的类型标记时,您会得到异常(例如:new TypeToken() {}
- 这是原始用法,当然在这里不起作用,重点是捕获 <>
中的内容)。
API麻烦!
您的 modelMapper.map
方法显然需要 Class<>
类型的值。如前所述,那些 不能 代表泛型,所以这个映射器只能映射到基本 typeargs-less 类型。在这种情况下,STT 完全矫枉过正,您只需要传递 class 个实例的简单解决方案。