Java泛型之Type

1、Type

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


image.png

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

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

2、ParameterizedType:参数化类型

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

Map map;
Set set1;
Class clz;
Holder holder;
List list;

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

Set set;
List aList;
T t;

2.1、ParameterizedType 的几个主要方法

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

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

2.2、Demo

public class ParameterizedTypeTest {

    private Map map;
    private Set set1;
    private Class clz;
    private Holder holder;
    private List list;
    private ArrayList arrayList; 
    private Map.Entry entry;

    private String str;
    private Integer i;
    private Set set;
    private List aList;

    static class Holder {
    }

    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 map)
     ParameterizedType:[class java.lang.String, class com.fsx.maintest.ParameterizedTypeTest]
     getRawType:interface java.util.Map
     getOwnerType:null
set1:(对应Set 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 holder)
     ParameterizedType:[class java.lang.String]
     getRawType:class com.fsx.maintest.ParameterizedTypeTest$Holder
     getOwnerType:class com.fsx.maintest.ParameterizedTypeTest
list:(对应List)
     ParameterizedType:[class java.lang.String]
     getRawType:interface java.util.List
     getOwnerType:null
arrayList:(对应ArrayList)
     ParameterizedType:[class java.lang.String]
     getRawType:class java.util.ArrayList
     getOwnerType:null
entry:(对应Map.Entry)
     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和V都是属于类型变量。
public test(T t){}方法中的以及参数中的T t都属于类型变量。

2.1、TypeVariable的主要方法

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

2.2、Demo

2.2.1、获取类的泛型类型

先定义一个泛型类

public class TestClass {
}

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

//获取类的泛型的类型
TypeVariable>[] classVariable = TestClass.class.getTypeParameters();
for (TypeVariable> classTypeVariable : classVariable) {
    Type[] bounds = classTypeVariable.getBounds();
    Class 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 {
  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;
    public  void test(T t, K k) {
    }
}

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

Method[] declaredMethods = TestClass.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    //获取方法定义的泛型类型
    TypeVariable[] typeParameters = declaredMethod.getTypeParameters();
    for (TypeVariable 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泛型类中声明了一个泛型方法 void test(T t, K k)

  • Method.getTypeParameters():返回的是定义在泛型方法上泛型类型的数组,对于泛型方法 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[] pTypeArray;
// 属于 GenericArrayType 组成元素是TypeVariable
T[] vTypeArray;
// 不属于 GenericArrayType
List list;
// 不属于 GenericArrayType
String[] strings;
// 不属于 GenericArrayType
Person[] ints;

Demo

public class TestClass {
    T[] t;
    TestClass[] testClassArray;
    List[] 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[] testClassArray)
    泛型数组中元素的类型:com.example.abu.serviceproject.TestClass
泛型数组:listArray:(对应List[] listArray)
    泛型数组中元素的类型:java.util.List
非泛型数组:(对应String[] strArray)strArray

4、WildcardType :通配符类型

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

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

下面一起来看一下例子。

public class WildcardTypeBean {

    private List a;  // a没有下界,
    //  没有指定的话,上边界默认是 Object ,下边界是  String
    private List b;

    private List c;

    private List 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)