Jor*_*Joh 2 java generics reflection
假设我有一些方法接受List<?>
public void method(List<?> list) {
// some logic
}
Run Code Online (Sandbox Code Playgroud)
如何在运行时获取元素类型?是否可以?
我发现了这些建议(在这里):
((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0](不起作用,List是一个接口并且没有超类)// ChatGPT's work
public class App {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
Type stringType = getListElementType(stringList);
Type integerType = getListElementType(integerList);
System.out.println("String List Element Type: " + stringType.getTypeName());
System.out.println("Integer List Element Type: " + integerType.getTypeName());
}
private static Type getListElementType(List<?> list) {
Type genericType = list.getClass().getGenericSuperclass();
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
return parameterizedType.getActualTypeArguments()[0];
}
throw new IllegalArgumentException("Unable to determine list element type.");
}
}
Run Code Online (Sandbox Code Playgroud)
控制台输出:
String List Element Type: E
Integer List Element Type: E
Run Code Online (Sandbox Code Playgroud)
List是只读的,而且它不能有任何实例字段,因为它是一个接口)String List Element Type: E
Integer List Element Type: E
Run Code Online (Sandbox Code Playgroud)
TypeResolver 类提供了以下一些方法:
Type reify(Type type, Class<S> context)使用上下文中的类型变量信息返回完全具体化的类型。
Type reify(Type genericType)使用泛型声明中的信息返回完全具体化的 genericType。
Class<?>[] resolveRawArguments(Class<T> type, Class<S> subType)使用子类型中的类型变量信息解析类型的原始参数。
Class<?> resolveRawArgument(Class<T> type, Class<S> subType)使用子类型中的类型变量信息解析类型的原始参数。
Type resolveGenericType(Class<?> type, Type subType)使用子类型中的类型变量信息解析泛型类型。
Class<?> resolveRawClass(Type genericType, Class<?> subType)使用子类型中的类型变量信息解析 genericType 的原始类。
如何在运行时获取元素类型?是否可以?
不。
泛型是编译器想象出来的。它们是一个链接使用类型的地方的工具,告诉编译器:这些类型需要相同 - 注入强制转换才能使其工作。如果您可以证明类型不对齐,则会生成编译错误。然后摆脱这一切。
唯一剩下的是签名中的泛型,但剩下的是您在源代码中编写的确切内容。不是实际类型。换句话说,给定:
public class MyExample<E> {
public void addAll(Collection<E> element) {
List<String> x = new ArrayList<String>();
check(x);
}
public void check(Object o) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
x变量的泛型完全消失了。没有什么 check可以恢复它是一个String. new ArrayList<String>()a和 a的内存占用量new ArrayList<Integer>()是100% 相同- 这不仅仅是“没有 API 来获取此信息”,而是更严格:这是不可能的。
您可以为类型 decl 本身以及方法element的参数获取泛型addAll- 但您实际上得到的是字母E。这是没用的。
所以,重复一遍:不。不可能。
TypeTools 的作用是滥用签名的生存方式,并将其与以下认识结合起来:
List<String> list = new ArrayList<String>();
Run Code Online (Sandbox Code Playgroud)
泛型部分被完全消除,其中:
List<String> list = new ArrayList<String>() {};
Run Code Online (Sandbox Code Playgroud)
它不是。这是因为大量的黑客攻击:
extends ArrayList<String>,并且具有类主体{}(如所示,它不添加任何内容)。类扩展的是“签名”,因此不会被删除,因此,在运行时您可以恢复这些东西。然而,因为它引入了一大堆警告,并且泛型是字面意思,所以这不是一个好主意。例如,如果我写:
public <E> createList() {
return new ArrayList<E>() {}
}
Run Code Online (Sandbox Code Playgroud)
这工作得很好,可以用例如:List<String> myList = ClassThatIsIn.<String>createList();- 尽管如此,SuperTypeTokens / typetools / 其他此类库在运行时唯一可以返回的是E- 字面意思。字母 E. 不String- 这是不可能的,因为它已被完全擦除。
因此,您的超级类型令牌附带一本手册和一长串注意事项。更一般地说,除了设计用于携带此类信息而没有其他任何内容(超类型令牌)之外的任何类型,都不是一个好主意。一种不执行任何操作的类型,它的全部作用就是供您编写SuperTypeToken<List<String>> myTokenRepresentingListOfStrings = new SuperTypeToken<List<String>>() {}。
如果您需要传达泛型可以捕获的内容(即不仅仅是一个类型,还包括该类型上的任何泛型),那么这种奇怪的黑客技术可能会很有用。例如,a Map<String, List<? extends Number>>- 不只是Map,不,整个事情 -java.lang.Class不能代表那个)。不要编写一个可以确定泛型是什么的方法。
没有解决方法。回到你最初的问题,考虑到:
public void method(List<?> list) {
// some logic
}
Run Code Online (Sandbox Code Playgroud)
答案是不。一大堆博客文章和文章都在拐弯抹角地提出了实现“是”的方法,但它们都是不正确的。没有办法做到。时期。超级类型标记/类型工具是完全不同的东西。没有办法使用这样的工具来让其成为“是”。
| 归档时间: |
|
| 查看次数: |
108 次 |
| 最近记录: |