WildcardType( 泛型表达式类型)
通配符表达式,或泛型表达式,它虽然是Type的一个子接口,但并不是Java类型中的一种,表示的仅仅是类似 ? extends T、? super K这样的通配符表达式。
?—通配符表达式,表示通配符泛型,但是WildcardType并不属于Java-Type中的一种
public interface WildcardType extends Type { //获得泛型表达式上界(上限) 获取泛型变量的上边界(extends) Type[] getUpperBounds(); //获得泛型表达式下界(下限) 获取泛型变量的下边界(super) Type[] getLowerBounds(); }
demo:
public class WildcardTypeTest { private List<? extends Number> listUpper; private List<? super String> listLower; private List<String> list; private Map<? extends String, ? super Number> map1; private Map<? extends String, ?> map2; private Class<?> clazz; // 不写泛型的list private List objList; private static void printWildcardType(WildcardType wildcardType) { for (Type type : wildcardType.getUpperBounds()) { System.out.println("\t\t上界:" + type); } for (Type type : wildcardType.getLowerBounds()) { System.out.println("\t\t下界:" + type); } } public static void main(String[] args) { Field f = null; try { Field[] fields = WildcardTypeTest.class.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { f = fields[i]; System.out.println("begin ******当前field:" + f.getName() + " *************************"); Type genericType = f.getGenericType(); // 获取字段的泛型参数 if (genericType instanceof ParameterizedType) { System.out.println("\tParameterizedType type :" + genericType); ParameterizedType parameterizedType = (ParameterizedType) genericType; for (Type type : parameterizedType.getActualTypeArguments()) { //参数化类型可能有多个 System.out.println("\t 获取到getActualTypeArguments为:" + type); if (type instanceof WildcardType) { printWildcardType((WildcardType) type); } } } else if (genericType instanceof GenericArrayType) { GenericArrayType genericArrayType = (GenericArrayType) genericType; System.out.println("\tGenericArrayType type :" + genericArrayType); Type genericComponentType = genericArrayType.getGenericComponentType(); if (genericComponentType instanceof WildcardType) { printWildcardType((WildcardType) genericComponentType); } } else if (genericType instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) genericType; System.out.println("\ttypeVariable:" + typeVariable); } else { System.out.println("\ttype :" + genericType); if (genericType instanceof WildcardType) { printWildcardType((WildcardType) genericType); } } System.out.println("end ******当前field:" + f.getName() + " *************************"); System.out.println(); } } catch (Exception e) { } } }
输出:
开始 ******当前field:listUpper ************************* ParameterizedType type :java.util.List<? extends java.lang.Number> 获取到getActualTypeArguments为:? extends java.lang.Number 上界:class java.lang.Number 结束 ******当前field:listUpper ************************* 开始 ******当前field:listLower ************************* ParameterizedType type :java.util.List<? super java.lang.String> 获取到getActualTypeArguments为:? super java.lang.String 上界:class java.lang.Object 下界:class java.lang.String 结束 ******当前field:listLower ************************* 开始 ******当前field:list ************************* ParameterizedType type :java.util.List<java.lang.String> 获取到getActualTypeArguments为:class java.lang.String 结束 ******当前field:list ************************* 开始 ******当前field:map1 ************************* ParameterizedType type :java.util.Map<? extends java.lang.String, ? super java.lang.Number> 获取到getActualTypeArguments为:? extends java.lang.String 上界:class java.lang.String 获取到getActualTypeArguments为:? super java.lang.Number 上界:class java.lang.Object 下界:class java.lang.Number 结束 ******当前field:map1 ************************* 开始 ******当前field:map2 ************************* ParameterizedType type :java.util.Map<? extends java.lang.String, ?> 获取到getActualTypeArguments为:? extends java.lang.String 上界:class java.lang.String 获取到getActualTypeArguments为:? 上界:class java.lang.Object 结束 ******当前field:map2 ************************* 开始 ******当前field:clazz ************************* ParameterizedType type :java.lang.Class<?> 获取到getActualTypeArguments为:? 上界:class java.lang.Object 结束 ******当前field:clazz ************************* 开始 ******当前field:objList ************************* type :interface java.util.List 结束 ******当前field:objList *************************
我们能够发现,字段的f.getGenericType()绝大部分都是返回的ParameterizedType类型,从而可以继续使用getActualTypeArguments拿到具体类型。看看是不是WildcardType类型
像这种private List objList,它f.getGenericType()直接就是interface java.util.List。
Map它可以有多个泛型表达式类型。另外需要说明的一点是:表达式中,如果你没有指定上线,默认都是有上限的:class java.lang.Object,但是下限不会有默认值
泛型中使用 & (并且)操作符
我们不乏有时候能够看到泛型搭配上 & 的使用方式,比如:
static <R extends Enum<R> & BaseIntEnum> List<R> parse2Enums(...){...}
首先说明一点:&
不能用于?
通配符上(因为通配符不能放在泛型的申明上)
&
只能放在泛型的声明上。比如类似这种:
public class WildcardTypeTest<T extends Comparable<T> & List<T> & Serializable> { ... } // 或者方法上申明泛型也成 static <R extends Enum<R> & BaseIntEnum> List<R> parse2Enums(...){...}
需要注意的是,
&
后面只能放置接口,而不能是具体类型。连Object都不行
因此当我们需要泛型的多重约束的时候,可以使用此并且&
操作符。但是它不能用于super
上,因为Java有规定:
class A<T extends Number> is allowed
but:
class A<T super Integer> is not allowed
原因请参考:Why super keyword in generics is not allowed at class level
下文也有详细分解
TypeVariable(类型变量)
泛型的类型变量,指的是List< T>、Map< K,V>中的T,K,V等值,实际的Java类型是TypeVariableImpl(TypeVariable的子类;此外,还可以对类型变量加上extend限定,这样会有类型变量对应的上限;值得注意的是,类型变量的上限可以为多个,必须使用&符号相连接,例如 List< T extends Number & Serializable>;其中,& 后必须为接口;
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement { //类型对应的上限,默认为Object 可以有多个 Type[] getBounds(); //获取声明该类型变量实体,也就是TypeVariableTest< T>中的TypeVariableTest D getGenericDeclaration(); //获取类型变量在源码中定义的名称; String getName(); // JDK8新增的 AnnotatedType[] getAnnotatedBounds(); }
demo:
public class TypeVariableTest<T extends Number & Serializable, V> { private T key; private V value; // 显然它本身是个GenericArrayType类型,里面是TypeVariable类型 private V[] values; //ParameterizedType 和 TypeVariable的结合 private List<T> tList; private String str; private static void printTypeVariable(String fieldName, TypeVariable typeVariable) { for (Type type : typeVariable.getBounds()) { System.out.println("\t\t" + fieldName + ": TypeVariable getBounds " + type); } System.out.println("\t\t定义Class getGenericDeclaration: " + typeVariable.getGenericDeclaration()); System.out.println("\t\tgetName: " + typeVariable.getName()); } public static void main(String[] args) { Field f = null; try { Field[] fields = TypeVariableTest.class.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { f = fields[i]; if (f.getName().equals("log")) { continue; } System.out.println("开始 ******当前field:" + f.getName() + " *************************"); Type genericType = f.getGenericType(); if (genericType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericType; for (Type type : parameterizedType.getActualTypeArguments()) { System.out.println("\t获取ParameterizedType:" + type); if (type instanceof TypeVariable) { printTypeVariable(f.getName(), (TypeVariable) type); } } System.out.println("\tgetOwnerType:" + parameterizedType.getOwnerType()); System.out.println("\tgetRawType:" + parameterizedType.getRawType()); } else if (genericType instanceof GenericArrayType) { GenericArrayType genericArrayType = (GenericArrayType) genericType; System.out.println("GenericArrayType type :" + genericArrayType); Type genericComponentType = genericArrayType.getGenericComponentType(); if (genericComponentType instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) genericComponentType; printTypeVariable(f.getName(), typeVariable); } } else if (genericType instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) genericType; printTypeVariable(f.getName(), typeVariable); } else { System.out.println("type :" + genericType); } System.out.println("结束 ******当前field:" + f.getName() + " *************************"); System.out.println(); } } catch (Exception e) { } } }
输出:
开始 ******当前field:key ************************* key: TypeVariable getBounds class java.lang.Number key: TypeVariable getBounds interface java.io.Serializable 定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest getName: T 结束 ******当前field:key ************************* 开始 ******当前field:value ************************* value: TypeVariable getBounds class java.lang.Object 定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest getName: V 结束 ******当前field:value ************************* 开始 ******当前field:values ************************* GenericArrayType type :V[] values: TypeVariable getBounds class java.lang.Object 定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest getName: V 结束 ******当前field:values ************************* 开始 ******当前field:tList ************************* 获取ParameterizedType:T tList: TypeVariable getBounds class java.lang.Number tList: TypeVariable getBounds interface java.io.Serializable 定义Class getGenericDeclaration: class com.fsx.maintest.TypeVariableTest getName: T getOwnerType:null getRawType:interface java.util.List 结束 ******当前field:tList ************************* 开始 ******当前field:str ************************* type :class java.lang.String 结束 ******当前field:str *************************
可以看出:TypeVariable是可以有多个的。可以使用getBounds拿出来,它返回的是数组(表名是支持多个的嘛)
V虽然啥都没写,但是也是有上限:java.lang.Object的
普通类型比如String,它啥都木有~~~~属于Class类型