Java泛型之Type

1挤聘、Type

Type是一個(gè)接口凡辱,是所有類型的父類眉尸,下圖展示了Type的繼承結(jié)構(gòu):


image.png

可以看到Type的子類有如下幾個(gè):

  • 1、Class:原始類型/基本類型
  • 2缘屹、ParameterizedType:參數(shù)化類型凛剥,在聲明含有泛型的變量就是參數(shù)化類型,無(wú)論其中的泛型有沒有具體的實(shí)現(xiàn)轻姿,如List<T> list1犁珠,List<String> list2都是參數(shù)化類型的。
  • 3踢代、TypeVariable:類型變量盲憎,其實(shí)代表的就是泛型尖括號(hào)中的東西,比如List<T>中的T胳挎,或者直接聲明一個(gè)泛型變量如private T t饼疙。
  • 4、WildcardType:通配符類型
  • 5慕爬、GenericArrayType:泛型數(shù)組類型

2窑眯、ParameterizedType:參數(shù)化類型

需要注意的是,并不只是 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 的幾個(gè)主要方法

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

1卷要、Type[] getActualTypeArguments()
getActualTypeArguments()獲取類型內(nèi)部的泛型的實(shí)際類型,如Map<String,Person> map 返回的是String類型和Person類型組成的Type的數(shù)組独榴。
2僧叉、Type getRawType()
getRawType()返回原始類型,如 Map<String,Person> map返回的就是Map類型
3棺榔、Type getOwnerType()
getOwnerType()獲取所有者類型瓶堕,只有內(nèi)部類才有所有者,如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 參數(shù)化類型的
                else {
                    System.out.println(f.getName() + ":is not ParameterizedType ");
                }
            }
        } catch (Exception e) {
        }
    }
}

輸出:

map:(對(duì)應(yīng)Map<String, ParameterizedTypeTest> map)
     ParameterizedType:[class java.lang.String, class com.fsx.maintest.ParameterizedTypeTest]
     getRawType:interface java.util.Map
     getOwnerType:null
set1:(對(duì)應(yīng)Set<String> set1)
     ParameterizedType:[class java.lang.String]
     getRawType:interface java.util.Set
     getOwnerType:null
clz:(對(duì)應(yīng)Class<?> clz)
     ParameterizedType:[?]
     getRawType:class java.lang.Class
     getOwnerType:null
holder:(對(duì)應(yīng)Holder<String> holder)
     ParameterizedType:[class java.lang.String]
     getRawType:class com.fsx.maintest.ParameterizedTypeTest$Holder
     getOwnerType:class com.fsx.maintest.ParameterizedTypeTest
list:(對(duì)應(yīng)List<String>)
     ParameterizedType:[class java.lang.String]
     getRawType:interface java.util.List
     getOwnerType:null
arrayList:(對(duì)應(yīng)ArrayList<String>)
     ParameterizedType:[class java.lang.String]
     getRawType:class java.util.ArrayList
     getOwnerType:null
entry:(對(duì)應(yīng)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>以及參數(shù)中的T t都屬于類型變量竞思。

2.1、TypeVariable的主要方法

  • Type[] getBounds(): 得到上邊界的Type數(shù)組钞护,如K的上邊界數(shù)組是InputStream 和 Serializable 盖喷。V沒有指定的話上邊界是Object。
  • D getGenericDeclaration():返回的是聲明該類型變量的實(shí)體难咕,如TypeVariableBean<K extends InputStream & Serializable, V>中的TypeVariableBean课梳。
  • String getName();返回的是這個(gè)type variable的名稱。

2.2余佃、Demo

2.2.1暮刃、獲取類的泛型類型

先定義一個(gè)泛型類

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("聲明該類型的實(shí)體:"+genericDeclaration.getName());
    System.out.println("名稱:"+name);
}

輸出

上邊界:[class java.lang.Object]
聲明該類型的實(shí)體:com.example.abu.serviceproject.TestClass
名稱:T

2.2.2、獲取類的屬性的泛型類型

在TextClass中聲明一個(gè)類型變量的屬性

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("聲明該類型的實(shí)體:"+genericDeclaration.getName());
            System.out.println("名稱:"+name);
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }

輸出

上邊界:[class java.lang.Object]
聲明該類型的實(shí)體:com.example.abu.serviceproject.TestClass
名稱:T

2.2.3爆土、獲取類的方法的泛型類型

在TestClass中創(chuàng)建一個(gè)方法

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

可以看到這里我們聲明了一個(gè)泛型方法test()椭懊,聲明了一個(gè)泛型<K>,并且接收兩個(gè)參數(shù)T tK k步势,這三個(gè)都是類型變量類型的氧猬,它們有什么區(qū)別呢?

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方法中聲明該類型的實(shí)體:" + genericDeclaration.getName());
    }
    //獲取方法參數(shù)的泛型類型
    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("方法中參數(shù)泛型的名稱:" + name + ":");
            System.out.println("\t方法參數(shù)中泛型的上邊界:" + Arrays.toString(bounds));
            if (genericDeclaration instanceof Class)
                System.out.println("\t方法中參數(shù)聲明該類型的實(shí)體:" + ((Class) genericDeclaration).getName());
            else if (genericDeclaration instanceof Method)
                System.out.println("\t方法中參數(shù)聲明該類型的實(shí)體:" + ((Method) genericDeclaration).getName());
        }
    }
}

輸出

方法泛型的名稱:K:
    方法泛型的上邊界:[class java.lang.Object]
    方法中聲明該類型的實(shí)體:test
方法中參數(shù)泛型的名稱:T:
    方法參數(shù)中泛型的上邊界:[class java.lang.Object]
    方法中參數(shù)聲明該類型的實(shí)體:com.example.abu.serviceproject.TestClass
方法中參數(shù)泛型的名稱:K:
    方法參數(shù)中泛型的上邊界:[class java.lang.Object]
    方法中參數(shù)聲明該類型的實(shí)體:test

我們?cè)?code>class TestClass<T>泛型類中聲明了一個(gè)泛型方法<K> void test(T t, K k)坏瘩。

  • Method.getTypeParameters():返回的是定義在泛型方法上泛型類型的數(shù)組盅抚,對(duì)于泛型方法<K> void test(T t, K k)來說就是K。由于是泛型是聲明在方法上的所以getGenericDeclaration返回的就是Method test()
  • Method.getGenericParameterTypes():返回的是方法中參數(shù)的泛型類型倔矾,test()方法有T t, K k兩個(gè)參數(shù)妄均,由于T是聲明在TestClass上的,K是聲明在方法上的,所以對(duì)于T getGenericDeclaration返回的就是Class TestClass哪自,而對(duì)于K getGenericDeclaration返回的就是Method test()丰包。

3、GenericArrayType:泛型數(shù)組

GenericArrayType是泛型數(shù)組提陶,組成數(shù)組的元素中有泛型的數(shù)組就是GenericArrayType類型的烫沙,組成數(shù)組的元素可以是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;
}

獲取類中的屬性是否是泛型數(shù)組類型隙笆,并獲取數(shù)組中元素的類型锌蓄。

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("泛型數(shù)組:" + fieldName + ":");
            GenericArrayType genericArrayType= (GenericArrayType) genericType;
            Type genericComponentType = genericArrayType.getGenericComponentType();
            System.out.println("\t泛型數(shù)組中元素的類型:"+genericComponentType);
        } else {
            System.out.println("非泛型數(shù)組:" + fieldName);
        }
    }
}

輸出

泛型數(shù)組:t: (對(duì)應(yīng)T[] t)
    泛型數(shù)組中元素的類型:T
泛型數(shù)組:testClassArray:(對(duì)應(yīng)TestClass<T>[] testClassArray)
    泛型數(shù)組中元素的類型:com.example.abu.serviceproject.TestClass<T>
泛型數(shù)組:listArray:(對(duì)應(yīng)List<String>[] listArray)
    泛型數(shù)組中元素的類型:java.util.List<java.lang.String>
非泛型數(shù)組:(對(duì)應(yīng)String[] strArray)strArray

4、WildcardType :通配符類型

<?>撑柔、<瘸爽?extends Number>、<? super Integer>這些都是通配符類型的铅忿,extends 用來指定上邊界剪决,沒有指定的話上邊界默認(rèn)是 Object, super 用來指定下邊界,沒有指定的話為 null柑潦。
幾個(gè)主要方法介紹

  • Type[] getLowerBounds() 得到上邊界 Type 的數(shù)組
  • Type[] getUpperBounds() 得到下邊界 Type 的數(shù)組

下面一起來看一下例子享言。

public class WildcardTypeBean<T> {

    private List<? extends Number> a;  // a沒有下界,
    //  沒有指定的話,上邊界默認(rèn)是 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("-----------------參數(shù)化類型-----------------");
                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]
下邊界:[]
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渗鬼,一起剝皮案震驚了整個(gè)濱河市览露,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌譬胎,老刑警劉巖差牛,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異堰乔,居然都是意外死亡偏化,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門镐侯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來侦讨,“玉大人,你說我怎么就攤上這事析孽〈钌耍” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵袜瞬,是天一觀的道長(zhǎng)怜俐。 經(jīng)常有香客問我,道長(zhǎng)邓尤,這世上最難降的妖魔是什么拍鲤? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮汞扎,結(jié)果婚禮上季稳,老公的妹妹穿的比我還像新娘。我一直安慰自己澈魄,他們只是感情好景鼠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著痹扇,像睡著了一般铛漓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鲫构,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天浓恶,我揣著相機(jī)與錄音,去河邊找鬼结笨。 笑死包晰,一個(gè)胖子當(dāng)著我的面吹牛湿镀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伐憾,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼勉痴,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了塞耕?” 一聲冷哼從身側(cè)響起蚀腿,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嘴瓤,失蹤者是張志新(化名)和其女友劉穎扫外,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體廓脆,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡筛谚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了停忿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驾讲。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖席赂,靈堂內(nèi)的尸體忽然破棺而出吮铭,到底是詐尸還是另有隱情,我是刑警寧澤颅停,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布谓晌,位于F島的核電站,受9級(jí)特大地震影響癞揉,放射性物質(zhì)發(fā)生泄漏纸肉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一喊熟、第九天 我趴在偏房一處隱蔽的房頂上張望柏肪。 院中可真熱鬧,春花似錦芥牌、人聲如沸烦味。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谬俄。三九已至,卻和暖如春扇商,著一層夾襖步出監(jiān)牢的瞬間凤瘦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工案铺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蔬芥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像笔诵,于是被迫代替她去往敵國(guó)和親返吻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354