gpt4 book ai didi

java - 如何获取List子类的REAL类型参数?

转载 作者:行者123 更新时间:2023-11-30 10:06:07 26 4
gpt4 key购买 nike

当我阅读 JavaFX 源代码时,在 com.sun.javafx.fxml.BeanAdapter , 静态方法 getGenericListItemType(Type) :

Determines the type of a list item.

但是,通过简单的测试用例,我发现这个实现可能有缺陷:

abstract class A<T> implements List<String> {}

abstract class B extends A<Integer> {}

abstract class C<S, T> implements List<T> {}

abstract class D extends C<String, Integer> {}

// in a function scope
BeanAdapter.getGenericListItemType(B.class) // expects String, gets Integer
BeanAdapter.getGenericListItemType(A.class) // works correctly

BeanAdapter.getGenericListItemType(D.class) // expects Integer, gets String

事实证明,这个有缺陷的实现只能处理 List<T> ← A<T> ← B<T> ← ... (parameterized) ... ← Y ← Z 模式的理想条件。

但是,当我尝试实现这个功能时,我发现它相当复杂。我想知道是否有可能获得真正的类型参数。如果可能,您能否提供一些提示或片段?

最佳答案

是的,这是可能的。

您可以创建一个 Map<TypeVariable<?>, Class<?>>并从给定的根类开始遍历类型图,以填充为每个类型变量提供的具体类型。例如:

public static Map<TypeVariable<?>, Class<?>> findTypeParameterValues(Class<?> cls) {
Map<TypeVariable<?>, Class<?>> parameterMap = new HashMap<>();
findTypeParameterValues(parameterMap, cls);
return parameterMap;
}

private static void findTypeParameterValues(Map<TypeVariable<?>, Class<?>> map, Class<?> cur) {
// create list of parameterized super types
List<ParameterizedType> pTypes = genericSuperTypes(cur)
.filter(ParameterizedType.class::isInstance)
.map(ParameterizedType.class::cast)
.collect(Collectors.toList());

for(ParameterizedType pType : pTypes) {
Type[] tArgs = pType.getActualTypeArguments(); // provided type arguments
Class<?> rawType = (Class<?>) pType.getRawType(); // (always a Class<?>)
TypeVariable<?>[] tParams = rawType.getTypeParameters(); // type parameters

for(int i = 0; i < tArgs.length; i++) { // iterate over both
Type tArg = tArgs[i]; // match type argument...
TypeVariable<?> tParam = tParams[i]; // with type parameter
Class<?> arg; // the value for the parameter
if(tArg instanceof Class<?>) {
// concrete argument
arg = (Class<?>) tArg;
} else if(tArg instanceof TypeVariable<?>) {
// concrete argument provided previously, or null
arg = map.get((TypeVariable<?>) tArg);
} else {
throw new UnsupportedOperationException("Unsupported type argument type: " + tArg);
}
map.put(tParam, arg); // put found value in map
}
}

superClasses(cur).forEach(pt -> findTypeParameterValues(map, pt));
}

private static Stream<Class<?>> superClasses(Class<?> cls) {
Stream.Builder<Class<?>> ret = Stream.builder();
ret.add(cls.getSuperclass());
Arrays.stream(cls.getInterfaces()).forEach(ret::add);
return ret.build().filter(Objects::nonNull);
}

private static Stream<Type> genericSuperTypes(Class<?> cls) {
Stream.Builder<Type> ret = Stream.builder();
ret.add(cls.getGenericSuperclass());
Arrays.stream(cls.getGenericInterfaces()).forEach(ret::add);
return ret.build().filter(Objects::nonNull);
}

然后将结果用于您的特定情况,您可以获得 List 类型变量的具体值从 map 上看:

public static void main(String[] args) throws Throwable {
System.out.println(getGenericListItemType(B.class)); // class java.lang.String
System.out.println(getGenericListItemType(A.class)); // class java.lang.String
System.out.println(getGenericListItemType(D.class)); // class java.lang.Integer
}

private static final TypeVariable<?> listE = List.class.getTypeParameters()[0];

public static Class<?> getGenericListItemType(Class<?> cls) {
// method defined in 'Reflection' helper class
return Reflection.findTypeParameterValues(cls).get(listE);
}

请注意,如果特定类型变量没有具体定义,映射将包含 null作为该类型变量的值。

关于java - 如何获取List子类的REAL类型参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54830511/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com