gpt4 book ai didi

java - 通配符类型到参数化类型

转载 作者:行者123 更新时间:2023-11-30 06:01:23 25 4
gpt4 key购买 nike

我有 List<? extends Number> 类型的 bean 属性以及候选实现类及其构造函数的列表。我递归地寻找构造函数参数的候选者。

候选构造函数之一是 ArrayList(Collection<? extends E>)

我正在尝试使用 Guava 解析类型参数和构造函数参数,但是当存在通配符类型链时,我得到类似以下内容的信息: ? extends capture#3-of ? extends capture#2-of ? extends capture#1-of ? extends ...

public static <T extends Object> void main(String[] args) throws Exception {
TypeToken<?> propTt = new TypeToken<List<? extends Number>>() {
};

TypeToken<?> candidate = propTt.getSubtype(ArrayList.class);

TypeToken<?> constructorResult;

Constructor<?> cons = ArrayList.class.getConstructor(Collection.class);

// java.util.ArrayList<? extends java.lang.Number>
constructorResult = candidate.constructor(cons).getReturnType();
System.out.println(constructorResult);


// java.util.Collection<? extends E>
Type param = cons.getGenericParameterTypes()[0];
System.out.println(param);

// java.util.Collection<? extends capture#1-of ? extends class java.lang.Number>
TypeToken<?> resolvedParam = constructorResult.resolveType(param);
System.out.println(resolvedParam);
}

尽管我们不能使用通配符作为 new 的类型参数,但还是会发生这种情况。 。以下内容是非法的:

List<?> x = new ArrayList<?>();
List<? extends Number> y = new ArrayList<? extends Number>();

我们这样写:

List<?> x = new ArrayList<Object>();
List<? extends Number> y = new ArrayList<Number>();

或使用菱形运算符自动执行后者。

所需类型 resolvedParamjava.util.Collection<? extends java.lang.Number> .

com.google.common.reflect.TypesnewParameterizedType()方法,我可以将以前的通配符手动解析为参数化类型或类,但此方法是包私有(private)的。我不确定我的解决方法:

package com.google.common.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.checkerframework.checker.nullness.qual.Nullable;

@SuppressWarnings("serial")
public class TestWildcard {
public static <T extends Object> void main(String[] args) throws Exception {
TypeToken<?> propTt = new TypeToken<List<? extends Number>>() {
};

TypeToken<?> candidate = propTt.getSubtype(ArrayList.class);

TypeToken<?> constructorResult;

Constructor<?> cons = ArrayList.class.getConstructor(Collection.class);

// new java.util.ArrayList<java.lang.Number>();
constructorResult = resolveConstructorResult(candidate);
System.out.println(constructorResult);

// java.util.Collection<? extends E>
Type param = cons.getGenericParameterTypes()[0];
System.out.println(param);

// java.util.Collection<? extends capture#1-of ? extends class java.lang.Number>
TypeToken<?> resolvedParam = constructorResult.resolveType(param);
System.out.println(resolvedParam);
}

static TypeToken<?> resolveConstructorResult(TypeToken<?> candidate) {
Type ct = candidate.getType();
if (ct instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) ct;
Class<?> ptClazz = ((Class<?>) pt.getRawType());
TypeVariable<?>[] tvars = ptClazz.getTypeParameters();
Type[] targs = pt.getActualTypeArguments();
boolean doIt = false;
for (int i = 0; i < targs.length; i++) {
if (targs[i] instanceof WildcardType) {
WildcardType wt = (WildcardType) targs[i];
TypeToken<?> ubound1 = TypeToken.of(wt.getUpperBounds()[0]);
TypeToken<?> ubound2 = TypeToken.of(tvars[i].getBounds()[0]);
if (ubound1.isSubtypeOf(ubound2)) {
doIt = true;
targs[i] = ubound1.getType();
} else if (ubound2.isSubtypeOf(ubound1)) {
doIt = true;
targs[i] = ubound2.getType();
}
}
}
if (doIt) {
pt = GuavaReflectAccessHelper.newParameterizedTypeWithOwner(pt.getOwnerType(), ptClazz, targs);
candidate = TypeToken.of(pt);
}
}
return candidate;
}

private static class GuavaReflectAccessHelper {

public static ParameterizedType newParameterizedTypeWithOwner(@Nullable Type ownerType, Class<?> rawType,
Type... arguments) {
return Types.newParameterizedTypeWithOwner(ownerType, rawType, arguments);
}
}
}

最佳答案

将通配符类型转换为 ParameterizedType 在这里听起来不太好,但您可以自己实现该接口(interface)。

或者使用其他一些支持更动态创建的库: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/TypeUtils.html
可能还有许多其他库。

在 Guava 中你只能做这样的事情:

static <K, V> TypeToken<Map<K, V>> mapToken(TypeToken<K> keyToken, TypeToken<V> valueToken) {
return new TypeToken<Map<K, V>>() {}
.where(new TypeParameter<K>() {}, keyToken)
.where(new TypeParameter<V>() {}, valueToken);
}
...
TypeToken<Map<String, BigInteger>> mapToken = mapToken(
TypeToken.of(String.class),
TypeToken.of(BigInteger.class));
TypeToken<Map<Integer, Queue<String>>> complexToken = mapToken(
TypeToken.of(Integer.class),
new TypeToken<Queue<String>>() {});

这对你来说可能就足够了。

关于java - 通配符类型到参数化类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52234172/

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