泛型的限制
要有效地使用Java泛型,必須考慮以下限制:
無(wú)法使用基元類型實(shí)例化泛型類型
無(wú)法創(chuàng)建類型參數(shù)的實(shí)例
無(wú)法聲明類型為類型參數(shù)的靜態(tài)字段
無(wú)法對(duì)參數(shù)化類型使用強(qiáng)制類型轉(zhuǎn)換或instanceof
無(wú)法創(chuàng)建參數(shù)化類型的數(shù)組
無(wú)法創(chuàng)建、捕獲或拋出參數(shù)化類型的對(duì)象
無(wú)法重載將每個(gè)重載的形式參數(shù)類型擦除為相同原始類型的方法
無(wú)法使用基元類型實(shí)例化泛型類型考慮以下參數(shù)化類型:
class Pair{ private K key; private V value; public Pair(K key, V value) { this.key = key; this.value = value; } // ... }
創(chuàng)建Pair對(duì)象時(shí),不能將基本類型替換為類型參數(shù)K或V:
Pairp = new Pair<>(8, "a"); // compile-time error
你只能將非基本類型替換為類型參數(shù)K和V:
Pairp = new Pair<>(8, "a");
請(qǐng)注意,Java編譯器將8自動(dòng)裝箱到Integer.valueOf(8),將"a"自動(dòng)裝箱到Character("a"):
Pairp = new Pair<>(Integer.valueOf(8), new Character("a"));
有關(guān)自動(dòng)裝箱的詳細(xì)信息,請(qǐng)參閱自動(dòng)裝箱和拆箱。
無(wú)法創(chuàng)建類型參數(shù)的實(shí)例你無(wú)法創(chuàng)建類型參數(shù)的實(shí)例,例如,以下代碼導(dǎo)致編譯時(shí)錯(cuò)誤:
public staticvoid append(List list) { E elem = new E(); // compile-time error list.add(elem); }
作為解決方法,你可以通過(guò)反射創(chuàng)建類型參數(shù)的對(duì)象:
public staticvoid append(List list, Class cls) throws Exception { E elem = cls.newInstance(); // OK list.add(elem); }
你可以按如下方式調(diào)用append方法:
List無(wú)法聲明類型為類型參數(shù)的靜態(tài)字段ls = new ArrayList<>(); append(ls, String.class);
類的靜態(tài)字段是類的所有非靜態(tài)對(duì)象共享的類級(jí)變量,因此,類型參數(shù)的靜態(tài)字段是不允許的,考慮以下類:
public class MobileDevice{ private static T os; // ... }
如果允許類型參數(shù)的靜態(tài)字段,則以下代碼將混淆:
MobileDevicephone = new MobileDevice<>(); MobileDevice pager = new MobileDevice<>(); MobileDevice pc = new MobileDevice<>();
因?yàn)殪o態(tài)字段os是由phone、pager和pc共享的,所以os的實(shí)際類型是什么?它不能同時(shí)是Smartphone、Pager和TabletPC,因此,你無(wú)法創(chuàng)建類型參數(shù)的靜態(tài)字段。
無(wú)法對(duì)參數(shù)化類型使用強(qiáng)制類型轉(zhuǎn)換或instanceof因?yàn)镴ava編譯器會(huì)擦除泛型代碼中的所有類型參數(shù),所以無(wú)法驗(yàn)證在運(yùn)行時(shí)使用泛型類型的參數(shù)化類型:
public staticvoid rtti(List list) { if (list instanceof ArrayList ) { // compile-time error // ... } }
傳遞給rtti方法的參數(shù)化類型集是:
S = { ArrayList, ArrayList LinkedList , ... }
運(yùn)行時(shí)不跟蹤類型參數(shù),因此它無(wú)法區(qū)分ArrayList
public static void rtti(List> list) { if (list instanceof ArrayList>) { // OK; instanceof requires a reifiable type // ... } }
通常,除非通過(guò)無(wú)界通配符對(duì)其進(jìn)行參數(shù)化,否則無(wú)法強(qiáng)制轉(zhuǎn)換為參數(shù)化類型,例如:
Listli = new ArrayList<>(); List ln = (List ) li; // compile-time error
但是,在某些情況下,編譯器知道類型參數(shù)始終有效并允許強(qiáng)制轉(zhuǎn)換,例如:
List無(wú)法創(chuàng)建參數(shù)化類型的數(shù)組l1 = ...; ArrayList l2 = (ArrayList )l1; // OK
你無(wú)法創(chuàng)建參數(shù)化類型的數(shù)組,例如,以下代碼無(wú)法編譯:
List[] arrayOfLists = new List [2]; // compile-time error
以下代碼說(shuō)明了將不同類型插入到數(shù)組中時(shí)會(huì)發(fā)生什么:
Object[] strings = new String[2]; strings[0] = "hi"; // OK strings[1] = 100; // An ArrayStoreException is thrown.
如果你使用泛型列表嘗試相同的操作,則會(huì)出現(xiàn)問(wèn)題:
Object[] stringLists = new List[]; // compiler error, but pretend it"s allowed stringLists[0] = new ArrayList (); // OK stringLists[1] = new ArrayList (); // An ArrayStoreException should be thrown, // but the runtime can"t detect it.
如果允許參數(shù)化列表數(shù)組,則前面的代碼將無(wú)法拋出所需的ArrayStoreException。
無(wú)法創(chuàng)建、捕獲或拋出參數(shù)化類型的對(duì)象泛型類不能直接或間接擴(kuò)展Throwable類,例如,以下類將無(wú)法編譯:
// Extends Throwable indirectly class MathExceptionextends Exception { /* ... */ } // compile-time error // Extends Throwable directly class QueueFullException extends Throwable { /* ... */ // compile-time error
方法無(wú)法捕獲類型參數(shù)的實(shí)例:
public staticvoid execute(List jobs) { try { for (J job : jobs) // ... } catch (T e) { // compile-time error // ... } }
但是,你可以在throws子句中使用類型參數(shù):
class Parser無(wú)法重載將每個(gè)重載的形式參數(shù)類型擦除為相同原始類型的方法{ public void parse(File file) throws T { // OK // ... } }
一個(gè)類不能有兩個(gè)在類型擦除后具有相同的簽名的重載方法。
public class Example { public void print(SetstrSet) { } public void print(Set intSet) { } }
重載將共享相同的類文件表示,并將生成編譯時(shí)錯(cuò)誤。
上一篇:類型擦除 下一篇:創(chuàng)建和使用包文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/72952.html
摘要:引用泛型除了方法因不能使用外部實(shí)例參數(shù)外,其他繼承實(shí)現(xiàn)成員變量,成員方法,方法返回值等都可使用。因此,生成的字節(jié)碼僅包含普通的類,接口和方法。 為什么要使用泛型程序設(shè)計(jì)? 一般的類和方法,只能使用具體的類型:要么是基本類型,要么是自定義類的對(duì)應(yīng)類型;如果要編寫(xiě)可以應(yīng)用于多種類型的代碼,這種刻板的限制對(duì)代碼的束縛就會(huì)很大。----摘自原書(shū)Ordinary classes and meth...
類型擦除 泛型被引入到Java語(yǔ)言中,以便在編譯時(shí)提供更嚴(yán)格的類型檢查并支持通用編程,為了實(shí)現(xiàn)泛型,Java編譯器將類型擦除應(yīng)用于: 如果類型參數(shù)是無(wú)界的,則用它們的邊界或Object替換泛型類型中的所有類型參數(shù),因此,生成的字節(jié)碼僅包含普通的類、接口和方法。 如有必要,插入類型轉(zhuǎn)換以保持類型安全。 生成橋接方法以保留擴(kuò)展泛型類型中的多態(tài)性。 類型擦除確保不為參數(shù)化類型創(chuàng)建新類,因此,泛型不會(huì)...
摘要:總結(jié)泛型的類型必須是引用類型,不能是基本類型,泛型的個(gè)數(shù)可以有多個(gè),可以使用對(duì)創(chuàng)建對(duì)象時(shí)的泛型類型以及方法參數(shù)類型進(jìn)行限制,如使用關(guān)鍵字和對(duì)泛型的具體類型進(jìn)行向下限制或向上限制,最后一點(diǎn),可以聲明泛型數(shù)組,但是不能創(chuàng)建泛型數(shù)組的實(shí)例。 自從 JDK 1.5 提供了泛型概念,泛型使得開(kāi)發(fā)者可以定義較為安全的類型,不至于強(qiáng)制類型轉(zhuǎn)化時(shí)出現(xiàn)類型轉(zhuǎn)化異常,在沒(méi)有反省之前,可以通過(guò) Object...
摘要:虛擬機(jī)中并沒(méi)有泛型類型對(duì)象,所有的對(duì)象都是普通類。其原因就是泛型的擦除。中數(shù)組是協(xié)變的,泛型是不可變的。在不指定泛型的情況下,泛型變量的類型為該方法中的幾種類型的同一個(gè)父類的最小級(jí),直到。 引入泛型的主要目標(biāo)有以下幾點(diǎn): 類型安全 泛型的主要目標(biāo)是提高 Java 程序的類型安全 編譯時(shí)期就可以檢查出因 Java 類型不正確導(dǎo)致的 ClassCastException 異常 符合越早出...
摘要:使用表示泛型中的基本思想就是可以通過(guò)使用像這樣適當(dāng)?shù)某悂?lái)實(shí)現(xiàn)泛型類。請(qǐng)看例子使用實(shí)現(xiàn)泛型使用接口類型表示泛型當(dāng)有多個(gè)類要在一個(gè)通用的方法里表示泛型時(shí),來(lái)表示可能就顯得捉襟見(jiàn)肘了,因?yàn)檫@個(gè)時(shí)候無(wú)法明確的知道用戶到底需要拆箱為哪種類。 1.1 使用Object表示泛型 Java中的基本思想就是可以通過(guò)使用像Object這樣適當(dāng)?shù)某悂?lái)實(shí)現(xiàn)泛型類。--《數(shù)據(jù)結(jié)構(gòu)與算法分析 Java語(yǔ)言描述...
閱讀 1209·2021-11-24 10:43
閱讀 3233·2021-11-22 09:34
閱讀 3608·2021-10-08 10:04
閱讀 4009·2021-09-23 11:58
閱讀 3165·2019-08-30 15:44
閱讀 540·2019-08-30 13:01
閱讀 1229·2019-08-28 18:07
閱讀 1501·2019-08-26 13:42