gpt4 book ai didi

java - 泛型和 java.beans.Introspector

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:40:58 26 4
gpt4 key购买 nike

给定以下代码框架,是否可以确定属性 foo 实际上是 String 类型?

public class TestIntrospection {
public static class SuperBean<T> {
private T foo;

public T getFoo() { return foo; }
public void setFoo(T foo) { this.foo = foo; }
}

public static class SubBean extends SuperBean<String> {
}

public static void main(String[] args) throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(SubBean.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor prop : propertyDescriptors) {
if ("foo".equals(prop.getName())) {
System.out.printf("%s of %s\n", prop.getName(), prop.getPropertyType());

Method readMethod = prop.getReadMethod();
Type returnType = prop.getReadMethod().getGenericReturnType();
if (returnType instanceof TypeVariable) {
TypeVariable t = (TypeVariable) returnType;
GenericDeclaration d = t.getGenericDeclaration();
System.out.println("TypeVariable : " + t.getName() + " " + t.getBounds()[0]);
}
}
}
}
}

实际输出为

foo of class java.lang.Object
TypeVariable : T class java.lang.Object

编辑:我应该提一下,我知道类型删除,而且该方法实际上是在字节码级别返回一个对象。尽管如此,关于泛型类型的元数据在类文件中是可用的,并且可以像示例代码中那样通过反射查询。这是另一个片段,显示 SubBean 实际上有一个 String 类型的类型参数:

                Type superClass = SubBean.class.getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) superClass;
System.out.println(pt.getActualTypeArguments()[0]);

输出:

class java.lang.String

问题仍然存在,我如何将这个实际类型参数与类型变量联系起来?如果我知道只有一个类型参数,这很简单,但我希望这段代码也适用于具有多个通用类型参数的 bean。

最佳答案

只要对象的运行时类确定了类型参数的值,您就可以通过用从 Class.getGenericSuperClass() 获得的实际类型参数递归替换形式类型参数来推断其实际值:

class Substitution extends HashMap<String, TypeExpr> {
Substitution(TypeVariable[] formals, TypeExpr[] actuals) {
for (int i = 0; i < actuals.length; i++) {
put(formals[i].getName(),actuals[i]);
}
}

}

abstract class TypeExpr {
abstract TypeExpr apply(Substitution s);

public abstract String toString();

static TypeExpr from(Type type) {
if (type instanceof TypeVariable) {
return new TypeVar((TypeVariable) type);
} else if (type instanceof Class) {
return new ClassType((Class) type);
} else if (type instanceof ParameterizedType) {
return new ClassType((ParameterizedType) type);
} else if (type instanceof GenericArrayType) {
return new ArrayType((GenericArrayType) type);
} else if (type instanceof WildcardType) {
return new WildcardTypeExpr((WildcardType) type);
}
throw new IllegalArgumentException(type.toString());
}

static TypeExpr[] from(Type[] types) {
TypeExpr[] t = new TypeExpr[types.length];
for (int i = 0; i < types.length; i++) {
t[i] = from(types[i]);
}
return t;
}

static TypeExpr[] apply(TypeExpr[] types, Substitution s) {
TypeExpr[] t = new TypeExpr[types.length];
for (int i = 0; i < types.length; i++) {
t[i] = types[i].apply(s);
}
return t;
}

static void append(StringBuilder sb, String sep, Object[] os) {
String s = "";
for (Object o : os) {
sb.append(s);
s = sep;
sb.append(o);
}
}
}

class TypeVar extends TypeExpr {
final String name;

public TypeVar(String name) {
this.name = name;
}

public TypeVar(TypeVariable var) {
name = var.getName();
}

@Override
public String toString() {
return name;
}

@Override
TypeExpr apply(Substitution s) {
TypeExpr e = s.get(name);
return e == null ? this : e;
}
}

class ClassType extends TypeExpr {
final Class clazz;
final TypeExpr[] arguments; // empty if the class is not generic

public ClassType(Class clazz, TypeExpr[] arguments) {
this.clazz = clazz;
this.arguments = arguments;
}

public ClassType(Class clazz) {
this.clazz = clazz;
arguments = from(clazz.getTypeParameters());
}

@Override
public String toString() {
String name = clazz.getSimpleName();
if (arguments.length == 0) {
return name;
}

StringBuilder sb = new StringBuilder();
sb.append(name);
sb.append("<");
append(sb, ", ", arguments);
sb.append(">");
return sb.toString();
}

public ClassType(ParameterizedType pt) {
clazz = (Class) pt.getRawType();
Type[] args = pt.getActualTypeArguments();
arguments = TypeExpr.from(args);
}

@Override
ClassType apply(Substitution s) {
return new ClassType(clazz, apply(arguments, s));
}
}

class ArrayType extends TypeExpr {
final TypeExpr componentType;

public ArrayType(TypeExpr componentType) {
this.componentType = componentType;
}

public ArrayType(GenericArrayType gat) {
this.componentType = TypeExpr.from(gat.getGenericComponentType());
}

@Override
public String toString() {
return componentType + "[]";
}

@Override
TypeExpr apply(Substitution s) {
return new ArrayType(componentType.apply(s));
}
}

class WildcardTypeExpr extends TypeExpr {
final TypeExpr[] lowerBounds;
final TypeExpr[] upperBounds;

public WildcardTypeExpr(TypeExpr[] lowerBounds, TypeExpr[] upperBounds) {
this.lowerBounds = lowerBounds;
this.upperBounds = upperBounds;
}

WildcardTypeExpr(WildcardType wct) {
lowerBounds = from(wct.getLowerBounds());
upperBounds = from(wct.getUpperBounds());
}

@Override
TypeExpr apply(Substitution s) {
return new WildcardTypeExpr(
apply(lowerBounds, s),
apply(upperBounds, s)
);
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("?");
if (lowerBounds.length > 0) {
sb.append(" super ");
append(sb, " & ", lowerBounds);
}
if (upperBounds.length > 0) {
sb.append(" extends ");
append(sb, " & ", upperBounds);
}
return sb.toString();
}
}

public class Test {

/**
* @return {@code superClazz}, with the replaced type parameters it has for
* instances of {@code ct}, or {@code null}, if {@code superClazz}
* is not a super class or interface of {@code ct}
*/
static ClassType getSuperClassType(ClassType ct, Class superClazz) {
if (ct.clazz == superClazz) {
return ct;
}

Substitution sub = new Substitution(ct.clazz.getTypeParameters(), ct.arguments);

Type gsc = ct.clazz.getGenericSuperclass();
if (gsc != null) {
ClassType sct = (ClassType) TypeExpr.from(gsc);
sct = sct.apply(sub);
ClassType result = getSuperClassType(sct, superClazz);
if (result != null) {
return result;
}
}

for (Type gi : ct.clazz.getGenericInterfaces()) {
ClassType st = (ClassType) TypeExpr.from(gi);
st = st.apply(sub);
ClassType result = getSuperClassType(st, superClazz);
if (result != null) {
return result;
}

}
return null;
}

public static ClassType getSuperClassType(Class clazz, Class superClazz) {
return getSuperClassType((ClassType) TypeExpr.from(clazz), superClazz);
}

测试代码:

    public static void check(Class c, Class sc, String expected) {
String actual = getSuperClassType(c, sc).toString();
if (!actual.equals(expected)) {
throw new AssertionError(actual + " != " + expected);
}
}

public static void main(String[] args) {
check(Substitution.class, Map.class, "Map<String, TypeExpr>");
check(HashMap.class, Map.class, "Map<K, V>");
check(Bar.class, Foo.class, "Foo<List<? extends String[]>>");
}
}

interface Foo<X> {

}
class SuperBar<X, Y> implements Foo<List<? extends Y[]>> {

}

class Bar<X> extends SuperBar<X, String> { }

另一方面,如果该类无法确定类型参数的值,则您必须扩展您的 bean 以在运行时通过其他方式保留实际类型参数的类对象,例如通过做:

class Super<T> {
final Class<T> clazz;

T foo;

Super(Class<T> clazz) {
this.clazz = clazz;
}

public T getFoo() {
return foo;
}

public T setFoo() {
this.foo = foo;
}
}

关于java - 泛型和 java.beans.Introspector,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4876380/

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