gpt4 book ai didi

java - 在其抽象父类(super class)中使用任何嵌套子类的泛型类型

转载 作者:行者123 更新时间:2023-12-02 01:45:48 25 4
gpt4 key购买 nike

假设您有以下抽象 java 类:

public abstract class AbstractRequestHandler<I,O> {
I input;
O output;
}

以及以下子类层次结构:

public abstract class AbstractUserRequestHandler<I extends User,O> extends AbstractRequestHandler<I,O>{...}
public abstract class AbstractUniversityRequestHandler<I extends UniversityUser> extends AbstractUserRequestHandler<I,String>{...}
public class StudentRequestHandler extends AbstractUniversityRequestHandler<Student>{...}
public class TeacherRequestHandler extends AbstractUniversityRequestHandler<Teacher>{...}

假设您需要在父类(super class)上的给定点使用泛型类型,例如,为了使用 gson 库在构造函数上将请求 json 反序列化为特定请求对象,如下所示:

public AbstractRequestHandler(final String inputJson) {
input = new Gson().fromJson(inputJson,typeOfI);
}

You need the type of generic I within variable "typeOfI"

是否有一个全局解决方案,允许获取由遵守以下约束的具体子类指定的泛型类型?

  1. 类型是在运行时获取的无论子类层次结构如何(该问题的示例也可能更复杂)
  2. 开发人员只需要定义扩展父类(super class)的泛型而无需在具体子类上的某个位置手动指定泛型类型(例如在重写的方法或构造函数上)

因此,如果您想定义一个新的具体子级,为泛型分配新值,您只需编写以下具体类即可:

public class StudentRequestHandler extends AbstractUniversityRequestHandler<Student>{

public StudentRequestHandler(String inputJson) {
super(inputJson);
}

}
<小时/>

我找到了以下解决方案,但它们不遵守所要求的解决方案约束。

打破约束n°2的解决方案

解决方案可能是在父类(super class)上定义一个抽象方法,如下所示

protected abstract Type getRequestType();

然后在定义泛型的每个具体子类上实现它:

public class StudentRequestHandler extends AbstractUniversityRequestHandler<Student>{

public StudentRequestHandler(String inputJson) {
super(inputJson);
}

@Override
protected Type getRequestType() {
return Student.class;
}
}

然后可以在目标父类(super class)的构造函数上使用 getRequestType() 方法:

public AbstractRequestHandler(final String inputJson) {
request = new Gson().fromJson(inputJson,getRequestType());
}

但即使它的工作原理与子类层次结构无关(尊重约束 n°1),开发人员也应该在每个具体子类上手动实现抽象方法。

打破约束n°1的解决方案

如果层次结构很简单,只有一个从目标父类(super class)扩展的直接子级,例如:

public class TeacherRequestHandler extends AbstractRequestHandler<Teacher,String>{...}

@naikus ( https://stackoverflow.com/users/306602/naikus ) 在以下 stackoverflow 线程上提出了一个可行的解决方案: Using a generic type of a subclass within it's abstract superclass?

但是,如果具体类不是定义泛型的父类(super class)的直接子类(如本问题中所建议的示例),则此方法不起作用。

最佳答案

编辑:在阅读您的答案并测试许多其他可能的情况后,我决定编辑您的代码并重新编写它以支持所有其他可能的边缘情况,包括跟踪深层嵌套的泛型在其他泛型类型中。

遗憾的是,为了支持所有情况,我们需要比您提供的更多的代码,泛型非常棘手,就像考虑这样的类:

private class SomeClass<A, B, C, D, E, F> {}

private class SomeConfusingClass<A> extends SomeClass<List<Void>[], List<? extends A>[], List<? extends A[][][]>[][][], List<? extends String[]>[], Map<List<? extends A[]>, A[][]>[], A> {}

private class TestClass extends SomeConfusingClass<Void> {}

为了开始这样做,我们需要有自己的 java 泛型类型实现,以便以后能够构造像 List<String>[] 这样的类型。因为无法使用原始 java API 动态创建此类类型。
这是在类似的库中处理泛型的非常流行的方法,您可以在 jackson 库等中看到类似的东西。
所以我们需要实现GenericArrayType , ParameterizedTypeWildcardType :

private static class ResolvedGenericArrayType implements GenericArrayType {
private final Type genericComponentType;

ResolvedGenericArrayType(Type genericComponentType) {
this.genericComponentType = genericComponentType;
}

@Override
public Type getGenericComponentType() {
return genericComponentType;
}

public String toString() {
return getGenericComponentType().toString() + "[]";
}

@Override
public boolean equals(Object o) {
if (o instanceof GenericArrayType) {
GenericArrayType that = (GenericArrayType) o;
return Objects.equals(genericComponentType, that.getGenericComponentType());
} else
return false;
}

@Override
public int hashCode() {
return Objects.hashCode(genericComponentType);
}
}

private static class ResolvedParameterizedType implements ParameterizedType {
private final Type[] actualTypeArguments;
private final Class<?> rawType;
private final Type ownerType;

private ResolvedParameterizedType(Type rawType, Type[] actualTypeArguments, Type ownerType) {
this.actualTypeArguments = actualTypeArguments;
this.rawType = (Class<?>) rawType;
this.ownerType = (ownerType != null) ? ownerType : this.rawType.getDeclaringClass();
}

public Type[] getActualTypeArguments() {
return actualTypeArguments.clone();
}

public Class<?> getRawType() {
return rawType;
}

public Type getOwnerType() {
return ownerType;
}

@Override
public boolean equals(Object o) {
if (!(o instanceof ParameterizedType)) {
return false;
}
ParameterizedType that = (ParameterizedType) o;
if (this == that)
return true;
Type thatOwner = that.getOwnerType();
Type thatRawType = that.getRawType();
return Objects.equals(ownerType, thatOwner) && Objects.equals(rawType, thatRawType) &&
Arrays.equals(actualTypeArguments, that.getActualTypeArguments());
}

@Override
public int hashCode() {
return Arrays.hashCode(actualTypeArguments) ^
Objects.hashCode(ownerType) ^
Objects.hashCode(rawType);
}

public String toString() {
StringBuilder sb = new StringBuilder();
if (ownerType != null) {
sb.append(ownerType.getTypeName());
sb.append("$");
if (ownerType instanceof ResolvedParameterizedType) {
sb.append(rawType.getName().replace(((ResolvedParameterizedType) ownerType).rawType.getName() + "$", ""));
} else
sb.append(rawType.getSimpleName());
} else
sb.append(rawType.getName());
if (actualTypeArguments != null) {
StringJoiner sj = new StringJoiner(", ", "<", ">");
sj.setEmptyValue("");
for (Type t : actualTypeArguments) {
sj.add(t.getTypeName());
}
sb.append(sj.toString());
}
return sb.toString();
}
}

private static class ResolvedWildcardType implements WildcardType {
private final Type[] upperBounds;
private final Type[] lowerBounds;

public ResolvedWildcardType(Type[] upperBounds, Type[] lowerBounds) {
this.upperBounds = upperBounds;
this.lowerBounds = lowerBounds;
}

public Type[] getUpperBounds() {
return upperBounds.clone();
}

public Type[] getLowerBounds() {
return lowerBounds.clone();
}

public String toString() {
Type[] lowerBounds = getLowerBounds();
Type[] bounds = lowerBounds;
StringBuilder sb = new StringBuilder();
if (lowerBounds.length > 0)
sb.append("? super ");
else {
Type[] upperBounds = getUpperBounds();
if (upperBounds.length > 0 && !upperBounds[0].equals(Object.class)) {
bounds = upperBounds;
sb.append("? extends ");
} else
return "?";
}
StringJoiner sj = new StringJoiner(" & ");
for (Type bound : bounds) {
sj.add(bound.getTypeName());
}
sb.append(sj.toString());
return sb.toString();
}

@Override
public boolean equals(Object o) {
if (o instanceof WildcardType) {
WildcardType that = (WildcardType) o;
return Arrays.equals(this.getLowerBounds(), that.getLowerBounds()) && Arrays.equals(this.getUpperBounds(), that.getUpperBounds());
} else
return false;
}

@Override
public int hashCode() {
Type[] lowerBounds = getLowerBounds();
Type[] upperBounds = getUpperBounds();
return Arrays.hashCode(lowerBounds) ^ Arrays.hashCode(upperBounds);
}
}

您基本上可以从 JDK 复制它们并进行一些清理。

我们需要的下一个实用程序是一个函数,用于在最后验证我们是否正确执行了所有操作,就像我们不想返回 Map<List<? extends X>[]> 一样。哪里X仍未解决TypeVariable :

private static boolean isDefined(Type type) {
if (type instanceof Class) {
return true;
}
if (type instanceof GenericArrayType) {
return isDefined(((GenericArrayType) type).getGenericComponentType());
}
if (type instanceof WildcardType) {
for (Type lowerBound : ((WildcardType) type).getLowerBounds()) {
if (!isDefined(lowerBound)) {
return false;
}
}
for (Type upperBound : ((WildcardType) type).getUpperBounds()) {
if (!isDefined(upperBound)) {
return false;
}
}
return true;
}
if (!(type instanceof ParameterizedType)) {
return false;
}
for (Type typeArgument : ((ParameterizedType) type).getActualTypeArguments()) {
if (!isDefined(typeArgument)) {
return false;
}
}
return true;
}

简单的递归函数将为我们完成此操作。我们只是检查每个可能的泛型类型并检查它的每个成员是否也已定义,除非我们会发现一些隐藏的 TypeVariable我们很好。
主函数可以与代码中的相同,我们只会在最后编辑该检查以使用我们的新函数:

public static Type getParameterizedType(Class<?> klass, Class<?> rootClass, int paramTypeNumber) throws GenericsException {

int targetClassParametersNumber = rootClass.getTypeParameters().length;
if (targetClassParametersNumber == 0) {
throw new GenericsException(String.format("Target class [%s] has no parameters type", rootClass.getName()));
} else if (targetClassParametersNumber - 1 < paramTypeNumber)
throw new GenericsException(String.format("Target class [%s] has parameters type which index start from [0] to [%s]. You requested instead parameter with index [%s]", rootClass, paramTypeNumber - 1, targetClassParametersNumber));

Type type = analyzeParameterizedTypes(klass, klass, rootClass, paramTypeNumber, null);
if (!isDefined(type))
throw new GenericsException(String.format("Parameter [%s] with index [%d] defined on class [%s] has not been valued yet on child class [%s]", type, paramTypeNumber, rootClass.getName(), klass.getName()));
return type;
}

现在让我们开始我们的主要工作

public static Type analyzeParameterizedTypes(final Class<?> klass, final Class<?> targetClass, final Class<?> rootClass, final int paramTypeNumber, Map<Integer, Type> childClassTypes) throws GenericsException { 

功能,乞讨保持不变,我们收集所有 TypeVariable到简单的 map ,保留从上一类的上一个循环中已经收集的信息。

    Type superclassType = klass.getGenericSuperclass();
Map<TypeVariable<?>, Type> currentClassTypes = new HashMap<>();
int z = 0;
if (childClassTypes != null) {
for (TypeVariable<?> variable : klass.getTypeParameters()) {
currentClassTypes.put(variable, childClassTypes.get(z));
z++;
}
}

然后我们有循环收集和精炼我们的类型参数:

    Map<Integer, Type> superClassesTypes = new HashMap<>();
if (superclassType instanceof ParameterizedType) {
int i = 0;
for (final Type argType : ((ParameterizedType) superclassType).getActualTypeArguments()) {
if (argType instanceof TypeVariable) {
superClassesTypes.put(i, currentClassTypes.containsKey(argType) ? currentClassTypes.get(argType) : argType);
} else {
superClassesTypes.put(i, refineType(klass, argType, currentClassTypesByName));
}
i++;
}
}

每个类型参数有 2 个路径,如果它的 TypeVariable 我们只是继续跟踪它,如果它有其他任何东西,我们尝试从任何可能的引用 TypeVariable 中“精炼”它。 。这是这段代码中最复杂的过程,这就是我们需要上面所有这些类的原因。 我们从这个处理所有可能类型的简单递归调度方法开始:

private static Type refineType(Type type, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
if (type instanceof Class) {
return type;
}
if (type instanceof GenericArrayType) {
return refineArrayType((GenericArrayType) type, typeVariablesMap);
}
if (type instanceof ParameterizedType) {
return refineParameterizedType((ParameterizedType) type, typeVariablesMap);
}
if (type instanceof WildcardType) {
return refineWildcardType((WildcardType) type, typeVariablesMap);
}
if (type instanceof TypeVariable) {
return typeVariablesMap.get(type);
}
throw new GenericsException("Unsolvable generic type: " + type);
}

以及在类型数组上运行它的小实用方法:

private static Type[] refineTypes(Type[] types, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
Type[] refinedTypes = new Type[types.length];
for (int i = 0; i < types.length; i++) {
refinedTypes[i] = refineType(types[i], typeVariablesMap);
}
return refinedTypes;
}

每种类型都进入自己的函数,或者如果它的TypeVariable我们只是从 map 中获取已解决的一个。注意,这个可以返回null,我这里没有处理。这一点以后可以改进。对于类,我们不需要做任何事情,所以我们可以返回类本身。

对于GenericArrayType我们需要首先找出这样的数组可能有多少维(这也可以通过我们的细化方法中的递归来处理,但在我看来调试起来有点困难):

private static int getArrayDimensions(GenericArrayType genericArrayType) {
int levels = 1;
GenericArrayType currentArrayLevel = genericArrayType;
while (currentArrayLevel.getGenericComponentType() instanceof GenericArrayType) {
currentArrayLevel = (GenericArrayType) currentArrayLevel.getGenericComponentType();
levels += 1;
}
return levels;
}

然后我们要提取数组的嵌套组件类型,因此对于 List<A>[][][]我们只想要List<A> :

private static Type getArrayNestedComponentType(GenericArrayType genericArrayType) {
GenericArrayType currentArrayLevel = genericArrayType;
while (currentArrayLevel.getGenericComponentType() instanceof GenericArrayType) {
currentArrayLevel = (GenericArrayType) currentArrayLevel.getGenericComponentType();
}
return currentArrayLevel.getGenericComponentType();
}

然后我们需要改进这个类型,所以我们的 List<A>将更改为例如 List<String> :

    Type arrayComponentType = refineType(getArrayNestedComponentType(genericArrayType), typeVariablesMap);

并使用精炼类型重建我们的通用结构,因此我们创建了 List<String>将变回List<String>[][][] :

private static Type buildArrayType(Type componentType, int levels) throws GenericsException {
if (componentType instanceof Class) {
return Array.newInstance(((Class<?>) componentType), new int[levels]).getClass();
} else if (componentType instanceof ParameterizedType) {
GenericArrayType genericArrayType = new ResolvedGenericArrayType(componentType);
for (int i = 1; i < levels; i++) {
genericArrayType = new ResolvedGenericArrayType(genericArrayType);
}
return genericArrayType;
} else {
throw new GenericsException("Array can't be of generic type");
}
}

整个函数如下所示:

private static Type refineArrayType( GenericArrayType genericArrayType, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
int levels = getArrayDimensions(genericArrayType);
Type arrayComponentType = refineType(getArrayNestedComponentType(genericArrayType), typeVariablesMap);
return buildArrayType(arrayComponentType, levels);
}

对于ParameterizedType它更简单,我们只需细化类型参数,并创建新的 ParameterizedType具有这些精炼参数的实例:

private static Type refineParameterizedType(ParameterizedType parameterizedType, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
Type[] refinedTypeArguments = refineTypes(parameterizedType.getActualTypeArguments(), typeVariablesMap);
return new ResolvedParameterizedType(parameterizedType.getRawType(), refinedTypeArguments, parameterizedType.getOwnerType());
}

同样适用于WildcardType :

private static Type refineWildcardType(WildcardType wildcardType, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
Type[] refinedUpperBounds = refineTypes(wildcardType.getUpperBounds(), typeVariablesMap);
Type[] refinedLowerBounds = refineTypes(wildcardType.getLowerBounds(), typeVariablesMap);
return new ResolvedWildcardType(refinedUpperBounds, refinedLowerBounds);
}

这给我们留下了整个分析函数,如下所示:

public static Type analyzeParameterizedTypes(final Class<?> klass, final Class<?> targetClass, final Class<?> rootClass, final int paramTypeNumber, Map<Integer, Type> childClassTypes) throws GenericsException {
Type superclassType = klass.getGenericSuperclass();
Map<TypeVariable<?>, Type> currentClassTypes = new HashMap<>();
int z = 0;
if (childClassTypes != null) {
for (TypeVariable<?> variable : klass.getTypeParameters()) {
currentClassTypes.put(variable, childClassTypes.get(z));
z++;
}
}

Map<Integer, Type> superClassesTypes = new HashMap<>();
if (superclassType instanceof ParameterizedType) {
int i = 0;
for (final Type argType : ((ParameterizedType) superclassType).getActualTypeArguments()) {
if (argType instanceof TypeVariable) {
superClassesTypes.put(i, currentClassTypes.getOrDefault(argType, argType));
} else {
superClassesTypes.put(i, refineType(argType, currentClassTypes));
}
i++;
}
}

if (klass != rootClass) {
final Class<?> superClass = klass.getSuperclass();
if (superClass == null)
throw new GenericsException(String.format("Class [%s] not found on class parent hierarchy [%s]", rootClass, targetClass));
return analyzeParameterizedTypes(superClass, targetClass, rootClass, paramTypeNumber, superClassesTypes);
}
return childClassTypes.get(paramTypeNumber);

}

使用示例:

private class SomeClass<A, B, C, D, E, F> {}
private class SomeConfusingClass<A> extends SomeClass<List<Void>[], List<? extends A>[], List<? extends A[][][]>[][][], List<? extends String[]>[], Map<List<? extends A[]>, A[][]>[], A> {}
private class TestClass extends SomeConfusingClass<Void> {}

public static void main(String[] args) throws Exception {
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 0));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 1));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 2));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 3));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 4));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 5));
}

结果:

java.util.List<java.lang.Void>[]
java.util.List<? extends java.lang.Void>[]
java.util.List<? extends java.lang.Void[][][]>[][][]
java.util.List<? extends java.lang.String[]>[]
java.util.Map<java.util.List<? extends java.lang.Void[]>, java.lang.Void[][]>[]
class java.lang.Void

带有测试的完整代码可以在这里找到:https://gist.github.com/GotoFinal/33b9e282f270dbfe61907aa830c27587或在这里:https://github.com/GotoFinal/generics-utils/tree/edge-cases-1

基于 OP 原始答案代码,但涵盖了大多数边缘情况。

关于java - 在其抽象父类(super class)中使用任何嵌套子类的泛型类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53686017/

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