美文网首页
Java泛型之Type

Java泛型之Type

作者: code希必地 | 来源:发表于2020-10-14 11:50 被阅读0次

    1、Type

    Type是一个接口,是所有类型的父类,下图展示了Type的继承结构:


    image.png

    可以看到Type的子类有如下几个:

    • 1、Class:原始类型/基本类型
    • 2、ParameterizedType:参数化类型,在声明含有泛型的变量就是参数化类型,无论其中的泛型有没有具体的实现,如List<T> list1,List<String> list2都是参数化类型的。
    • 3、TypeVariable:类型变量,其实代表的就是泛型尖括号中的东西,比如List<T>中的T,或者直接声明一个泛型变量如private T t。
    • 4、WildcardType:通配符类型
    • 5、GenericArrayType:泛型数组类型

    2、ParameterizedType:参数化类型

    需要注意的是,并不只是 Collection<String> 才是 parameterized,任何类似于 ClassName<V> 这样的类型都是 ParameterizedType ,比如下面的这些都是 parameterizedType.

    Map<String, Person> map;
    Set<String> set1;
    Class<?> clz;
    Holder<String> holder;
    List<String> list;
    

    而类似于这样的 ClassName 不是 ParameterizedType。

    Set set;
    List aList;
    T t;
    

    2.1、ParameterizedType 的几个主要方法

    • Type[] getActualTypeArguments();
    • Type getRawType();
    • Type getOwnerType();

    1、Type[] getActualTypeArguments()
    getActualTypeArguments()获取类型内部的泛型的实际类型,如Map<String,Person> map 返回的是String类型和Person类型组成的Type的数组。
    2、Type getRawType()
    getRawType()返回原始类型,如 Map<String,Person> map返回的就是Map类型
    3、Type getOwnerType()
    getOwnerType()获取所有者类型,只有内部类才有所有者,如Map.Entry<String, String> entry 的 getOwnerType() 返回的就是Map类型,而Map<String,String>则返回null。

    2.2、Demo

    public class ParameterizedTypeTest {
    
        private Map<String, ParameterizedTypeTest> map;
        private Set<String> set1;
        private Class<?> clz;
        private Holder<String> holder;
        private List<String> list;
        private ArrayList<String> arrayList; 
        private Map.Entry<String, String> entry;
    
        private String str;
        private Integer i;
        private Set set;
        private List aList;
    
        static class Holder<V> {
        }
    
        public static void main(String[] args) {
            Field f = null;
            try {
                // 拿到所有的字段
                Field[] fields = ParameterizedTypeTest.class.getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {
                    f = fields[i];
    
    
                    if (f.getGenericType() instanceof ParameterizedType) {
                        ParameterizedType parameterizedType = (ParameterizedType) f.getGenericType();
                        System.out.println(f.getName() + ":");
    
                        System.out.println("\t ParameterizedType:" + Arrays.asList(parameterizedType.getActualTypeArguments()));
                        System.out.println("\t getRawType:" + parameterizedType.getRawType());
                        System.out.println("\t getOwnerType:" + parameterizedType.getOwnerType());
                    }
                    // 输出不是ParameterizedType 参数化类型的
                    else {
                        System.out.println(f.getName() + ":is not ParameterizedType ");
                    }
                }
            } catch (Exception e) {
            }
        }
    }
    

    输出:

    map:(对应Map<String, ParameterizedTypeTest> map)
         ParameterizedType:[class java.lang.String, class com.fsx.maintest.ParameterizedTypeTest]
         getRawType:interface java.util.Map
         getOwnerType:null
    set1:(对应Set<String> set1)
         ParameterizedType:[class java.lang.String]
         getRawType:interface java.util.Set
         getOwnerType:null
    clz:(对应Class<?> clz)
         ParameterizedType:[?]
         getRawType:class java.lang.Class
         getOwnerType:null
    holder:(对应Holder<String> holder)
         ParameterizedType:[class java.lang.String]
         getRawType:class com.fsx.maintest.ParameterizedTypeTest$Holder
         getOwnerType:class com.fsx.maintest.ParameterizedTypeTest
    list:(对应List<String>)
         ParameterizedType:[class java.lang.String]
         getRawType:interface java.util.List
         getOwnerType:null
    arrayList:(对应ArrayList<String>)
         ParameterizedType:[class java.lang.String]
         getRawType:class java.util.ArrayList
         getOwnerType:null
    entry:(对应Map.Entry<String,String>)
         ParameterizedType:[class java.lang.String, class java.lang.String]
         getRawType:interface java.util.Map$Entry
         getOwnerType:interface java.util.Map
    str:is not ParameterizedType 
    i:is not ParameterizedType 
    set:is not ParameterizedType 
    aList:is not ParameterizedType 
    

    2、TypeVariable:类型变量

    比如 :
    public T t,属于类型变量。t属于类型变量。
    public class TypeVariableBean<K extends InputStream & Serializable, V> , K和V都是属于类型变量。
    public <T> test(T t){}方法中的<T>以及参数中的T t都属于类型变量。

    2.1、TypeVariable的主要方法

    • Type[] getBounds(): 得到上边界的Type数组,如K的上边界数组是InputStream 和 Serializable 。V没有指定的话上边界是Object。
    • D getGenericDeclaration():返回的是声明该类型变量的实体,如TypeVariableBean<K extends InputStream & Serializable, V>中的TypeVariableBean
    • String getName();返回的是这个type variable的名称。

    2.2、Demo

    2.2.1、获取类的泛型类型

    先定义一个泛型类

    public class TestClass<T> {
    }
    

    获取该泛型类的泛型的类型

    //获取类的泛型的类型
    TypeVariable<Class<TestClass>>[] classVariable = TestClass.class.getTypeParameters();
    for (TypeVariable<Class<TestClass>> classTypeVariable : classVariable) {
        Type[] bounds = classTypeVariable.getBounds();
        Class<TestClass> genericDeclaration = classTypeVariable.getGenericDeclaration();
        String name = classTypeVariable.getName();
        System.out.println("上边界:"+Arrays.toString(bounds));
        System.out.println("声明该类型的实体:"+genericDeclaration.getName());
        System.out.println("名称:"+name);
    }
    

    输出

    上边界:[class java.lang.Object]
    声明该类型的实体:com.example.abu.serviceproject.TestClass
    名称:T
    

    2.2.2、获取类的属性的泛型类型

    在TextClass中声明一个类型变量的属性

    public class TestClass<T> {
      private T t;
    }
    

    获取属性的泛型类型

    try {
            Field field = TestClass.class.getDeclaredField("t");
            Type genericType = field.getGenericType();
            if (genericType instanceof TypeVariable) {
                TypeVariable typeVariable= (TypeVariable) genericType;
                Class genericDeclaration = (Class) typeVariable.getGenericDeclaration();
                Type[] bounds = typeVariable.getBounds();
                String name = typeVariable.getName();
                System.out.println("上边界:"+Arrays.toString(bounds));
                System.out.println("声明该类型的实体:"+genericDeclaration.getName());
                System.out.println("名称:"+name);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    

    输出

    上边界:[class java.lang.Object]
    声明该类型的实体:com.example.abu.serviceproject.TestClass
    名称:T
    

    2.2.3、获取类的方法的泛型类型

    在TestClass中创建一个方法

    public class TestClass<T> {
        T t;
        public <K> void test(T t, K k) {
        }
    }
    

    可以看到这里我们声明了一个泛型方法test(),声明了一个泛型<K>,并且接收两个参数T tK k,这三个都是类型变量类型的,它们有什么区别呢?

    Method[] declaredMethods = TestClass.class.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        //获取方法定义的泛型类型
        TypeVariable<Method>[] typeParameters = declaredMethod.getTypeParameters();
        for (TypeVariable<Method> typeParameter : typeParameters) {
            Method genericDeclaration = typeParameter.getGenericDeclaration();
            Type[] bounds = typeParameter.getBounds();
            String name = typeParameter.getName();
            System.out.println("方法泛型的名称:" + name+":");
            System.out.println("\t方法泛型的上边界:" + Arrays.toString(bounds));
            System.out.println("\t方法中声明该类型的实体:" + genericDeclaration.getName());
        }
        //获取方法参数的泛型类型
        Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            if (genericParameterType instanceof TypeVariable) {
                TypeVariable typeVariable = (TypeVariable) genericParameterType;
                GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
                Type[] bounds = typeVariable.getBounds();
                String name = typeVariable.getName();
                System.out.println("方法中参数泛型的名称:" + name + ":");
                System.out.println("\t方法参数中泛型的上边界:" + Arrays.toString(bounds));
                if (genericDeclaration instanceof Class)
                    System.out.println("\t方法中参数声明该类型的实体:" + ((Class) genericDeclaration).getName());
                else if (genericDeclaration instanceof Method)
                    System.out.println("\t方法中参数声明该类型的实体:" + ((Method) genericDeclaration).getName());
            }
        }
    }
    

    输出

    方法泛型的名称:K:
        方法泛型的上边界:[class java.lang.Object]
        方法中声明该类型的实体:test
    方法中参数泛型的名称:T:
        方法参数中泛型的上边界:[class java.lang.Object]
        方法中参数声明该类型的实体:com.example.abu.serviceproject.TestClass
    方法中参数泛型的名称:K:
        方法参数中泛型的上边界:[class java.lang.Object]
        方法中参数声明该类型的实体:test
    

    我们在class TestClass<T>泛型类中声明了一个泛型方法<K> void test(T t, K k)

    • Method.getTypeParameters():返回的是定义在泛型方法上泛型类型的数组,对于泛型方法<K> void test(T t, K k)来说就是K。由于是泛型是声明在方法上的所以getGenericDeclaration返回的就是Method test()
    • Method.getGenericParameterTypes():返回的是方法中参数的泛型类型,test()方法有T t, K k两个参数,由于T是声明在TestClass上的,K是声明在方法上的,所以对于T getGenericDeclaration返回的就是Class TestClass,而对于K getGenericDeclaration返回的就是Method test()。

    3、GenericArrayType:泛型数组

    GenericArrayType是泛型数组,组成数组的元素中有泛型的数组就是GenericArrayType类型的,组成数组的元素可以是ParameterizedType类型的也可以是TypeVariable类型的。

    // 属于 GenericArrayType 组成元素是ParameterizedType 
    List<String>[] pTypeArray;
    // 属于 GenericArrayType 组成元素是TypeVariable
    T[] vTypeArray;
    // 不属于 GenericArrayType
    List<String> list;
    // 不属于 GenericArrayType
    String[] strings;
    // 不属于 GenericArrayType
    Person[] ints;
    

    Demo

    public class TestClass<T> {
        T[] t;
        TestClass<T>[] testClassArray;
        List<String>[] listArray;
        String[] strArray;
    }
    

    获取类中的属性是否是泛型数组类型,并获取数组中元素的类型。

    public void test() {
        Field[] declaredFields = TestClass.class.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            Type genericType = declaredField.getGenericType();
            String fieldName = declaredField.getName();
            if (genericType instanceof GenericArrayType) {
                System.out.println("泛型数组:" + fieldName + ":");
                GenericArrayType genericArrayType= (GenericArrayType) genericType;
                Type genericComponentType = genericArrayType.getGenericComponentType();
                System.out.println("\t泛型数组中元素的类型:"+genericComponentType);
            } else {
                System.out.println("非泛型数组:" + fieldName);
            }
        }
    }
    

    输出

    泛型数组:t: (对应T[] t)
        泛型数组中元素的类型:T
    泛型数组:testClassArray:(对应TestClass<T>[] testClassArray)
        泛型数组中元素的类型:com.example.abu.serviceproject.TestClass<T>
    泛型数组:listArray:(对应List<String>[] listArray)
        泛型数组中元素的类型:java.util.List<java.lang.String>
    非泛型数组:(对应String[] strArray)strArray
    

    4、WildcardType :通配符类型

    <?>、<?extends Number>、<? super Integer>这些都是通配符类型的,extends 用来指定上边界,没有指定的话上边界默认是 Object, super 用来指定下边界,没有指定的话为 null。
    几个主要方法介绍

    • Type[] getLowerBounds() 得到上边界 Type 的数组
    • Type[] getUpperBounds() 得到下边界 Type 的数组

    下面一起来看一下例子。

    public class WildcardTypeBean<T> {
    
        private List<? extends Number> a;  // a没有下界,
        //  没有指定的话,上边界默认是 Object ,下边界是  String
        private List<? super String> b;
    
        private List<String> c;
    
        private List<T> list;
    
        private Class<?> aClass;
    }
    
     public void testWildCardType() {
        Field[] fields = WildcardTypeBean.class.getDeclaredFields();
        for (Field field : fields) {
            Type genericType = field.getGenericType();
            if (genericType instanceof WildcardType)
                System.out.println(field.getName() + " is WildcardType");
            else if (genericType instanceof ParameterizedType){
                System.out.println(field.getName() + " is  ParameterizedType");
                ParameterizedType parameterizedType= (ParameterizedType) genericType;
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                Type actualTypeArgument=actualTypeArguments[0];
                if(actualTypeArgument instanceof WildcardType){
                    WildcardType wildcardType= (WildcardType) actualTypeArgument;
                    System.out.println("-----------------通配符类型-----------------");
                    System.out.println("name:"+wildcardType.getTypeName());
                    System.out.println("上边界:"+Arrays.toString(wildcardType.getUpperBounds()));
                    System.out.println("下边界:"+Arrays.toString(wildcardType.getLowerBounds()));
                }else if(actualTypeArgument instanceof ParameterizedType){
                    System.out.println("-----------------参数化类型-----------------");
                    System.out.println("name:"+actualTypeArgument.getTypeName());
                }else if(actualTypeArgument instanceof TypeVariable){
                    System.out.println("-----------------类型变量-----------------");
                    System.out.println("name:"+actualTypeArgument.getTypeName());
                }else if(actualTypeArgument instanceof Class){
                    System.out.println("-----------------原始类型-----------------");
                    System.out.println("name:"+actualTypeArgument.getTypeName());
                }
            }
    
        }
    
    }
    

    输出

    a is  ParameterizedType
    -----------------通配符类型-----------------
    name:? extends java.lang.Number
    上边界:[class java.lang.Number]
    下边界:[]
    
    b is  ParameterizedType
    -----------------通配符类型-----------------
    name:? super java.lang.String
    上边界:[class java.lang.Object]
    下边界:[class java.lang.String]
    
    c is  ParameterizedType
    -----------------原始类型-----------------
    name:java.lang.String
    
    list is  ParameterizedType
    -----------------类型变量-----------------
    name:T
    
    aClass is  ParameterizedType
    -----------------通配符类型-----------------
    name:?
    上边界:[class java.lang.Object]
    下边界:[]
    

    相关文章

      网友评论

          本文标题:Java泛型之Type

          本文链接:https://www.haomeiwen.com/subject/nvnbpktx.html