JDK 泛型之 Type

JDK 泛型之 Type

1、Type 接口

JDK 1.5 引入 Type,主要是爲了泛型,沒有泛型的以前,只有所謂的原始類型。此時,全部的原始類型都經過字節碼文件類 Class 類進行抽象。Class 類的一個具體對象就表明一個指定的原始類型。java

泛型出現後擴充了數據類型,從只有原始類型擴充了參數化類型、類型變量類型、泛型數組類型。Type 的子接口有:ParameterizedType、TypeVariable、GenericArrayType、WildcardType,實現類有 Class。git

Type 接口

Type 體系中類型的包括:原始類型(Class)、基本類型(Class)、類型變量(TypeVariable)、參數化類型(ParameterizedType)、數組類型(GenericArrayType)。github

  • 原始類型(Class):不只僅包含咱們日常所指的類,還包括枚舉、數組、註解等;
  • 基本類型(Class):也就是咱們所說的 java 的基本類型,即 int, float, double 等;
  • 類型變量(TypeVariable):各類類型變量的公共父接口,就是泛型裏面的相似 T、E,即泛型變量;
  • 參數化類型(ParameterizedType):就是咱們日常所用到的泛型 List、Map;
  • 數組類型(GenericArrayType):並非咱們工做中所使用的數組 String[] 、byte[],而是泛型數組 T[] ;
// 1. 原始類型(Class)
Set set;
List aList;
String[] arr;

// 2. 參數化類型(ParameterizedType)
Map<String, Person> map;
Set<String> set;
Class<?> clazz;
List<String> list;

// 3. 類型變量(TypeVariable)
T t;

// 4. 數組類型(GenericArrayType)
Class<?>[] clazz;
Map<String, Person>[] clazz;

1、參數化類型(ParameterizedType)

ParameterizedType,參數化類型,形如:Object<T, K>,即常說的泛型,是 Type 的子接口。spring

public interface ParameterizedType extends Type {
    // 1. 得到<>中實際類型
    Type[] getActualTypeArguments();

    // 2. 得到 <> 前面實際類型
    Type getRawType();

    // 3. 若是這個類型是某個類型所屬,得到這個全部者類型,不然返回 null
    Type getOwnerType();
}

(1) getActualTypeArguments數組

返回這個 Type 類型的參數的實際類型數組,即 <> 裏的類型參數的類型,由於可能有多個類型參數,例如 Map<K, V>,因此返回的是一個 Type[] 數組。.net

【注意】不管 <> 中有幾層 <> 嵌套,這個方法僅僅脫去最外層的 <>,以後剩下的內容就做爲這個方法的返回值,因此其返回值類型不必定。code

public class ParameterizedTypeTest<T> {
    List<Set> a1;           // 返回 Set,Class 類型
    List<Set<String>> a2;   // 返回 Set<String>,ParameterizedType 類型
    List<T> a3;             // 返回 T,TypeVariable 類型
    List<? extends Set> a4; // 返回 WildcardType 類型
    List<Set<String>[]> a5; // 返回 GenericArrayType 類型

    @Test
    public void test1() throws Exception {
        Method method = getClass().getMethod("test", List.class);
        Type[] types = method.getGenericParameterTypes();
        ParameterizedType pType = (ParameterizedType) types[0];
        Type[] type = pType.getActualTypeArguments();
        // sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
        System.out.println(type[0].getClass().getName());
    }

    public void test(List<ArrayList<String>[]> a) {
    }
}

(2) getRawType對象

返回的是當前這個 ParameterizedType 的類型,即最外層 <> 前面那個類型,如 Map<K ,V> 的 Mapblog

Map.Entry<String, Integer> me;
@Test
public void rawTypeTest() throws Exception {
    Field field = getClass().getDeclaredField("me");
    ParameterizedType type = (ParameterizedType) field.getGenericType();
    // java.util.Map$Entry
    System.out.println(type.getRawType());
}

(3) getOwnerType接口

返回的是這個 ParameterizedType 所在的類的 Type。

Map.Entry<String, Integer> me;
@Test
public void ownerTypeTest() throws Exception {
    Field field = getClass().getDeclaredField("me");
    ParameterizedType type = (ParameterizedType) field.getGenericType();
    // java.util.Map
    System.out.println(type.getOwnerType());
}

3、TypeVariable(類型變量)

TypeVariable 描述所謂範型變量,也就是 或者

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
    // 變量上邊界數組,沒有指定的話是 Object
    Type[] getBounds();

    // 獲取變量被定義在什麼 GenericDeclaration 上
    D getGenericDeclaration();

    // 獲取變量名字
    String getName();

    // jdk 1.8
    AnnotatedType[] getAnnotatedBounds();
}
  • getBounds 獲得上邊界的 Type 數組,如 K 的上邊界數組是 InputStream 和 Serializable。V 沒有指定的話,上邊界是 Object
  • getGenericDeclaration 返回的是聲明這個 Type 所在的類 的 Type
  • getName 返回的是這個 type variable 的名稱

(1) getBounds

獲取泛型變量的上邊界的 Type 數組,若是沒有指定則是 Object。

@Test
public void test() {
    // 1. 獲取類上聲明的泛型變量 getTypeParameters
    TypeVariable<Class<TypeVariable>> typeVariable = TypeVariable.class.getTypeParameters()[0];
    // 2. 獲取泛型變量的上邊界 java.lang.reflect.GenericDeclaration
    System.out.println(Arrays.toString(typeVariable.getBounds()));
}

(2) getGenericDeclaration

GenericDeclaration 該接口用來定義哪些對象上是能夠聲明範型變量,目前實現 GenericDeclaration 接口的類包括 Class、Method、Constructor,也就是說只能在這幾種對象上進行範型變量的聲明(定義)。

public class TypeVariableTest<E> {
    @Test
    public void getGenericDeclarationTest() {
        // 1. 類上聲明泛型
        TypeVariable<Class<TypeVariableTest>> classType = TypeVariableTest.class.getTypeParameters()[0];
        Class<TypeVariableTest> clazzDeclaration = classType.getGenericDeclaration();
        // class com.github.binarylei.spring01.day0728.test.TypeVariableTest
        System.out.println(clazzDeclaration);

        // 2. 方法上聲明泛型
        Method[] methods = TypeVariableTest.class.getMethods();
        Method method = Arrays.stream(methods)
                .filter(m -> m.getName().equals("test"))
                .collect(Collectors.toList())
                .get(0);
        TypeVariable methodType = (TypeVariable) method.getGenericParameterTypes()[0];
        GenericDeclaration methodDeclaration = methodType.getGenericDeclaration();
        // public void com.github.binarylei.TypeVariableTest.test(java.lang.Object)
        System.out.println(methodDeclaration);

        // 3. 構造器上聲明泛型
    }

    public <T> void test(T t) {
    }
}

4、GenericArrayType(數組類型)

範型數組,組成數組的元素中有範型則實現了該接口;它的組成元素是 ParameterizedType 或 TypeVariable 類型

public interface GenericArrayType extends Type {
    // 得到這個數組元素類型,即得到:A<T>(A<T>[])或T(T[])
    Type getGenericComponentType();
}

下面咱們一塊兒來看一下例子:

classA<K>[][] key;

Type type = Main.class.getDeclaredField("key").getGenericType();
// com.github.binarylei..classA<K>[]
System.out.println(((GenericArrayType)type).getGenericComponentType());

5、WildcardType(通配符的類型)

WildcardType,通配符表達式,Type 子接口,可是在 Java 中並無 WildcardType 類型。extends 用來指定上邊界,沒有指定的話上邊界默認是 Object,super 用來指定下邊界,沒有指定的話爲 null。

幾個主要方法介紹:

public interface WildcardType extends Type {
    Type[] getUpperBounds();
    Type[] getLowerBounds();
}
  • getLowerBounds 獲得上邊界 Type 的數組

  • getUpperBounds 獲得下邊界 Type 的數組

下面一塊兒來看一下例子:

public class WildcardTypeTest {

    // 指定上界 Number,下邊界默認爲 []
    private List<? extends Number> a;
    // 指定下界 String,上邊界默認是 Object
    private List<? super String> b;
    // 上界和下界都不指定,上邊界默認是 Object,下邊界默認爲 []
    private Class<?> clazz;

    // 沒有通配符,不是 WildcardType
    private List<String> c;

    @Test
    public void test() throws Exception {
        Field[] fields = WildcardTypeTest.class.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            Type type = field.getGenericType();
            String nameString = field.getName();
            //1. 先拿到範型類型
            if (!(type instanceof ParameterizedType)) {
                continue;
            }

            //2. 再從範型裏拿到通配符類型
            ParameterizedType parameterizedType = (ParameterizedType) type;
            type = parameterizedType.getActualTypeArguments()[0];
            if (!(type instanceof WildcardType)) {
                continue;
            }

            System.out.println("-------------" + nameString + "--------------");
            WildcardType wildcardType = (WildcardType) type;
            Type[] lowerTypes = wildcardType.getLowerBounds();
            if (lowerTypes != null) {
                System.out.println("下邊界:" + Arrays.toString(lowerTypes));
            }
            Type[] upTypes = wildcardType.getUpperBounds();
            if (upTypes != null) {
                System.out.println("上邊界:" + Arrays.toString(upTypes));
            }
        }
    }
}

6、GenericDeclaration

GenericDeclaration 該接口用來定義哪些對象上是能夠聲明範型變量,目前實現 GenericDeclaration 接口的類包括 Class、Method、Constructor,也就是說只能在這幾種對象上進行範型變量的聲明(定義)。

GenericDeclaration 的接口方法 getTypeParameters 用來逐個獲取該 GenericDeclaration 的範型變量聲明。

public interface GenericDeclaration extends AnnotatedElement {
    // 用來獲取該GenericDeclaration的範型變量聲明
    public TypeVariable<?>[] getTypeParameters();
}

(1) 泛型的聲明

//1. 在類(Class)上聲明
class A<T> { T a; }

// 2. 在方法上聲明
//   類型變量聲明不是在參數裏邊,並且必須在返回值以前,static 等修飾後
public <E> void test(E e) {}

// 3. 在構造器上聲明
public <K> A(K k) {}

【注意】類型變量聲明(定義)的時候不能有下限(既不能有 super),不然編譯報錯。爲何?T extends classA 表示泛型有上限 classA,固然能夠,由於這樣,每個傳進來的類型一定是 classA(具備 classA 的一切屬性和方法),但如果 T super classA,傳進來的類型不必定具備 classA 的屬性和方法,固然就不適用於泛型,說的具體點:

class A<T super classA>{
    T t;
    public void test(){
        // t 的子類是 classA,咱們仍是不知道 t 究竟是什麼類型,不知道 t 有那些方法
    }
}

參考:

  1. 《Type - Java類型》:http://www.javashuo.com/article/p-utzdmukn-n.html

天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索