【小家Java】你真的了解Java泛型参数吗?细说java.lang.reflect.Type(ParameterizedType、TypeVariable、WildcardType...)(中)

简介: 【小家Java】你真的了解Java泛型参数吗?细说java.lang.reflect.Type(ParameterizedType、TypeVariable、WildcardType...)(中)

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类型

相关文章
|
2月前
|
Java
实现java执行kettle并传参数
实现java执行kettle并传参数
38 1
|
3月前
|
Java API
[Java]泛型
本文详细介绍了Java泛型的相关概念和使用方法,包括类型判断、继承泛型类或实现泛型接口、泛型通配符、泛型方法、泛型上下边界、静态方法中使用泛型等内容。作者通过多个示例和测试代码,深入浅出地解释了泛型的原理和应用场景,帮助读者更好地理解和掌握Java泛型的使用技巧。文章还探讨了一些常见的疑惑和误区,如泛型擦除和基本数据类型数组的使用限制。最后,作者强调了泛型在实际开发中的重要性和应用价值。
92 0
[Java]泛型
|
2月前
|
Java
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
|
3月前
|
存储 安全 Java
🌱Java零基础 - 泛型详解
【10月更文挑战第7天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
28 1
|
3月前
|
Java 语音技术 容器
java数据结构泛型
java数据结构泛型
38 5
|
3月前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
30 1
|
3月前
|
存储 算法 Java
java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
这篇文章是关于如何在Java中使用Graphics2D的RenderingHints方法来提高海报制作的图像质量和文字清晰度,包括抗锯齿和解决文字不清晰问题的技术详解。
116 0
java制作海报六:Graphics2D的RenderingHints方法参数详解,包括解决文字不清晰,抗锯齿问题
|
3月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
29 2
|
3月前
|
Java
java构造方法时对象初始化,实例化,参数赋值
java构造方法时对象初始化,实例化,参数赋值
109 1
|
4月前
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `&lt;&gt;` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。

热门文章

最新文章