Java中的Type類型

Type的定義

/**
 * Type is the common superinterface for all types in the Java
 * programming language. These include raw types, parameterized types,
 * array types, type variables and primitive types.
 *
 * @since 1.5
 */
public interface Type {}

翻譯成中文,大致如下:

在Java編程語言中干旧,Type是所有類型的父接口驹吮。包括:

  1. 原始類型(raw types),對(duì)應(yīng)Class實(shí)現(xiàn)類
  2. 參數(shù)化類型(parameterized types)痰腮,對(duì)應(yīng)ParameterizedType接口
  3. 泛型數(shù)組類型(array types),對(duì)應(yīng)GenericArrayType接口
  4. 類型變量(type variables)律罢,對(duì)應(yīng)TypeVariable接口
  5. 基本類型(primitive types)膀值,對(duì)應(yīng)Class實(shí)現(xiàn)類
  6. 通配符類型(wildcard types),對(duì)應(yīng)WildcardType接口

一個(gè)簡(jiǎn)單的例子

public class Main {

    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Method method = Main.class.getMethod("testType",
                List.class, List.class, List.class, List.class, List.class, Map.class);

        // 按照聲明順序返回`Type對(duì)象`的數(shù)組
        Type[] types = method.getGenericParameterTypes();

        for (int i = 0; i < types.length; i++) {
            // 最外層都是ParameterizedType
            ParameterizedType pType = (ParameterizedType) types[i];
            // 返回表示此類型【實(shí)際類型參數(shù)】的`Type對(duì)象`的數(shù)組
            Type[] actualTypes = pType.getActualTypeArguments();
            for (int j = 0; j < actualTypes.length; j++) {
                Type actualType = actualTypes[j];
                System.out.print("(" + i + ":" + j + ")  類型【" + actualType + "】");
                if (actualType instanceof Class) {
                    System.out.println(" -> 類型接口【" + actualType.getClass().getSimpleName() + "】");
                } else {
                    System.out.println(" -> 類型接口【" + actualType.getClass().getInterfaces()[0].getSimpleName() + "】");
                }
            }
        }
    }

    public <T> void testType(List<String> a1,
                             List<ArrayList<String>> a2,
                             List<T> a3,
                             List<? extends Number> a4,
                             List<ArrayList<String>[]> a5,
                             Map<String, Integer> a6) {
    }
}

執(zhí)行以上代碼误辑,我們得到以下結(jié)果:

(0:0)  類型【class java.lang.String】 -> 類型接口【Class】
(1:0)  類型【java.util.ArrayList<java.lang.String>】 -> 類型接口【ParameterizedType】
(2:0)  類型【T】 -> 類型接口【TypeVariable】
(3:0)  類型【? extends java.lang.Number】 -> 類型接口【W(wǎng)ildcardType】
(4:0)  類型【java.util.ArrayList<java.lang.String>[]】 -> 類型接口【GenericArrayType】
(5:0)  類型【class java.lang.String】 -> 類型接口【Class】
(5:1)  類型【class java.lang.Integer】 -> 類型接口【Class】

類型可能出現(xiàn)的場(chǎng)景

  1. 修飾類的繼承(extends)或?qū)崿F(xiàn)(implements)關(guān)系類型
  2. 修飾類的參數(shù)類型
  3. 修飾字段的類型
  4. 修飾方法的請(qǐng)求參數(shù)類型
  5. 修飾方法的返回參數(shù)類型

ParameterizedType

ParameterizedType沧踏,叫做參數(shù)化類型,也叫泛型巾钉,指的是帶尖括號(hào)的修飾符類型悦冀。例如:List<T>Map<Integer, String>睛琳、List<? extends Number>盒蟆。

方法 - Type[] getActualTypeArguments();

  1. 表示此類型實(shí)際類型參數(shù)的Type對(duì)象的數(shù)組。
  2. 也就是說师骗,獲得參數(shù)化類型中<>里面的類型參數(shù)的類型历等。
  3. 可能有多個(gè)類型參數(shù),例如Map<K, V>辟癌。

方法 - Type getRawType();

  1. 返回Type對(duì)象寒屯,表示聲明此類型的類或接口。
  2. 簡(jiǎn)單來說就是:返回最外層<>前面那個(gè)類型黍少,例如Map<K ,V>寡夹,針對(duì)K或V來說,返回的就是Map類型厂置。

方法 - Type getOwnerType();

  1. 返回Type對(duì)象菩掏,表示此類型是其成員之一的類型。
  2. 如果當(dāng)前類型為頂層類型昵济,則返回null(通常情況是這樣)智绸。
  3. 例如:Map.Entry中的Entry返回的就是Map野揪,A.B.C中的C返回的就是A$B

例子

public class Main {

    public static void main(String[] args) throws Exception {
        Method method = Main.class.getMethod("calc", List.class);
        Type[] types = method.getGenericParameterTypes();
        ParameterizedType listType = (ParameterizedType) types[0];
        System.out.println("listType.getRawType() is Class: " + (listType.getRawType() instanceof Class));
        System.out.println("listType.getRawType() return: " + listType.getRawType().getTypeName());

        ParameterizedType abctType = (ParameterizedType) listType.getActualTypeArguments()[0];
        System.out.println("abctType.getOwnerType() is Class: " + (abctType.getOwnerType() instanceof Class));
        System.out.println("abctType.getOwnerType() return: " + abctType.getOwnerType());
    }

    public <T> void calc(List<A.B.C<T>> list) {
    }

    interface A<T> {
        interface B<T> {
            interface C<T> {
            }
        }
    }
}

返回結(jié)果如下:

listType.getRawType() is Class: true
listType.getRawType() return: java.util.List
abctType.getOwnerType() is Class: true
abctType.getOwnerType() return: interface com.junconcurrent.Main$A$B

TypeVariable

TypeVariable瞧栗,叫做類型變量斯稳,泛指任意類。例如:參數(shù)化類型中的E迹恐、K挣惰、V、T等殴边。

方法 - Type[] getBounds();

  1. 返回表示此類型變量上邊界的Type對(duì)象的數(shù)組憎茂。
  2. 【注意】:如果未顯式聲明上邊界,則上邊界為Object找都。
  3. 【主要】:在類型變量中唇辨,只能有上邊界廊酣,不能有下邊界能耻。例如:V super Xxx,將編譯報(bào)錯(cuò)亡驰。

方法 - D getGenericDeclaration();

返回表示聲明此類型變量的泛型聲明的GenericDeclaration對(duì)象晓猛。

方法 - String getName();

返回此類型變量的名稱,因?yàn)樗霈F(xiàn)在源代碼中凡辱。

方法 - AnnotatedType[] getAnnotatedBounds();

返回AnnotatedType對(duì)象的數(shù)組戒职,這些對(duì)象表示使用類型來表示此TypeVariable表示的類型參數(shù)的上限。

例子

public class Main {

    public static void main(String[] args) throws Exception {
        Method method = Main.class.getMethod("calc", List.class);
        Type[] types = method.getGenericParameterTypes();
        ParameterizedType listType = (ParameterizedType) types[0];
        System.out.println("listType.getRawType() is Class: " + (listType.getRawType() instanceof Class));
        System.out.println("listType.getRawType() return: " + listType.getRawType().getTypeName());

        TypeVariable abctType = (TypeVariable) listType.getActualTypeArguments()[0];
        System.out.println("abctType.getName() return: " + abctType.getName());
        System.out.println("abctType.getBounds() return: " + Arrays.toString(abctType.getBounds()));
        System.out.println("abctType.getGenericDeclaration() return: " + abctType.getGenericDeclaration());
    }

    public <T extends String & Map> void calc(List<T> list) {
    }
}

返回結(jié)果如下:

listType.getRawType() is Class: true
listType.getRawType() return: java.util.List
abctType.getName() return: T
abctType.getBounds() return: [class java.lang.String, interface java.util.Map]
abctType.getGenericDeclaration() return: public void com.junconcurrent.Main.calc(java.util.List)

GenericArrayType

GenericArrayType透乾,叫做泛型數(shù)組類型洪燥,其組件類型為參數(shù)化類型或類型變量。例如:List<T>[]乳乌、T[]捧韵。其和一般數(shù)組類型不太一樣。如果方括號(hào)去掉之后的類型是參數(shù)化類型或者類型變量汉操,那么其就是GenericArrayType再来。否則為一般數(shù)組類型,例如:List[]磷瘤、String[]芒篷,其類型為Class

方法 - Type getGenericComponentType();

返回表示此數(shù)組的組件類型的Type對(duì)象采缚。此方法用于獲取數(shù)組的組件類型针炉。

獲取泛型數(shù)組中元素的類型,要注意的是:無論從左向右有幾個(gè)[]并列扳抽,這個(gè)方法僅僅脫去最右邊的[]糊识,之后剩下的內(nèi)容就作為這個(gè)方法的返回值绩社。

WildcardType

WildcardType為通配符類型表達(dá)式。例如:?赂苗、? super T愉耙、? extends T? extends Number拌滋。

方法 - Type[] getUpperBounds();

返回表示此類型變量上邊界的Type對(duì)象的數(shù)組朴沿。

【注意】:如果不存在顯式聲明的上邊界,則上邊界為Object败砂。

方法 - Type[] getLowerBounds();

返回表示此類型變量下邊界的Type對(duì)象的數(shù)組赌渣。

【注意】:如果不存在顯式聲明的下邊界,則下邊界為類型 null昌犹。在此情況下懒震,將返回長(zhǎng)度為零的數(shù)組。

Class

除了上述4種類型之外激捏,通常的類型或者原始類型武花,都是Class類型。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铸敏,一起剝皮案震驚了整個(gè)濱河市缚忧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杈笔,老刑警劉巖闪水,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蒙具,居然都是意外死亡球榆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門禁筏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來持钉,“玉大人,你說我怎么就攤上這事融师∮壹兀” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵旱爆,是天一觀的道長(zhǎng)舀射。 經(jīng)常有香客問我,道長(zhǎng)怀伦,這世上最難降的妖魔是什么脆烟? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮房待,結(jié)果婚禮上邢羔,老公的妹妹穿的比我還像新娘驼抹。我一直安慰自己,他們只是感情好拜鹤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布框冀。 她就那樣靜靜地躺著,像睡著了一般敏簿。 火紅的嫁衣襯著肌膚如雪明也。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天惯裕,我揣著相機(jī)與錄音温数,去河邊找鬼。 笑死蜻势,一個(gè)胖子當(dāng)著我的面吹牛撑刺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播握玛,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼够傍,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了败许?” 一聲冷哼從身側(cè)響起王带,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤淑蔚,失蹤者是張志新(化名)和其女友劉穎市殷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刹衫,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡醋寝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了带迟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片音羞。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖仓犬,靈堂內(nèi)的尸體忽然破棺而出嗅绰,到底是詐尸還是另有隱情,我是刑警寧澤搀继,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布窘面,位于F島的核電站,受9級(jí)特大地震影響叽躯,放射性物質(zhì)發(fā)生泄漏财边。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一点骑、第九天 我趴在偏房一處隱蔽的房頂上張望酣难。 院中可真熱鬧谍夭,春花似錦憨募、人聲如沸紧索。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽齐板。三九已至,卻和暖如春葛菇,著一層夾襖步出監(jiān)牢的瞬間甘磨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工眯停, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留济舆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓莺债,卻偏偏與公主長(zhǎng)得像滋觉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子齐邦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355