国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

[Effective Java]第五章 泛型

2019-11-14 22:44:29
字體:
來源:轉載
供稿:網友
[Effective java]第五章 泛型聲明:原創作品,轉載時請注明文章來自SAP師太技術博客( 博/客/園www.cnblogs.com):m.survivalescaperooms.com/jiangzhengjun,并以超鏈接形式標明文章原始出處,否則將追究法律責任!原文鏈接:http://m.survivalescaperooms.com/jiangzhengjun/p/4255654.html 第五章 泛型23、 請不要在新代碼中使用原生態類型

聲明中具有一個或者多個類型參數的類或者接口,就是泛型類或者泛型接口。泛型類和接口統稱為泛型。

每種泛型可以定義一種參數化的類型,格式為:先是類或者接口的名稱,接著用尖括號(<>)把對應于泛型的類型參數的實際類型參數列表括起來。

每個泛型都定義一個原生態類型,即不帶任何實際類型參數的泛型名稱,也是沒有泛型之前的類型。

泛型能將運行時期的錯誤提前到編譯時期檢測。

如果使用原生態類型,就失掉了泛型在安全性和表述性方面的所有優勢。既然不應該使用原生態類型,為什么Java設計還要允許使用它們呢?這是為了提供兼容性,要兼容以前沒有使用泛型的Java代碼。

原生態類型List和參數化的類型List<Object>之間到底有什么區別呢?不嚴格地說,前者逃避了泛型檢查,后者則明確告知編譯器,它能夠持有任意類型的對象。泛型有子類型化的規則:List<String>是原生態類型List的一個子類型,而不是參數化類型List<Object>的子類型(見25條)。因此,如果用不用像List這樣的原生態類型,就會失掉類型安全性,但是如果使用像List<Object>這樣的參數化類型,則不會。

在無限制通配類型Set<?>和原生態類型Set之間有什么區別呢?由于可以將任何元素放進使用原生態類型的集合中,因此很容易破壞該集合的類型約束條件;但不能將任何元素(除了null之外)放到Collection<?>中。

“不要在新代碼中使用原生態類型”,這條規則有兩個例外,這是因為“泛型信息在運行時就會被擦除”。在獲取類信息中必須使用原生態類型(數組類型和基本類型也算原生態類型),規范不允許使用參數化類型。換句話說:List.class,String[].class和int.class都是合法,但是List<String>.class和List<?>.class都是不合法的。這條規則的第二個例外與instanceof操作符有關,由于泛型信息在運行時已被擦除,因此在參數化類型而不是無限制通配符類型(如List<?>)上使用instanceof操作符是非法的,用無限制通配符類型代替原生態類型,對instanceof操作的行為不產生任何影響。在這種情況下,尖括號<>和問號?就顯得多余了。下面是利用泛型來使用instanceof操作符的首先方法:

if(o instanceof set){

Set<?> m = (Set<?>)o;

// ...

}

注意,一旦確定這個o是個Set,就必須將它轉換成通配類型Set<?>,則不是轉換成原生態類型Set,否則Set會引起編譯時警告。

總之,使用原生態類型會在運行時導致異常,因此不要在新代碼中使用。原生態類型只為了與引入泛型之前的遺留代碼進行兼容和互用而提供的。另外Set<Object>是個參數化類型,表示可以包括任何對象類型的一個集合;Set<?>則是一個通配符類型,表示只能包含某種未知對象類型的一個集合;Set則是個原生態類型,它脫離了泛型系統。前兩者是安全的,最后一種不安全。

術語介紹:

原生態類型:List

參數化的類型:List<String>

泛型:List<E>

有限制類型參數:List<E extends Number>

形式類型參數:E

無限制通配符類型:List<?>

有限制通配符類型:List<? extends Number>

遞歸類型限制:List <T extends Comparable<T>>

泛型方法:static<E> List<E> asList(E[] a)

24、 消除非受檢警告

用泛型編程時,會遇到許多編譯器警告:非受檢強制轉換警告、非受檢方法調用警告、非受檢普通數組創建警告,以及非受檢轉換警告。

要盡可能地消除每一個非受檢警告。如果消除了所有警告,就可以確保代碼是類型安全的。

如果無法消除警告,同時可以證明引起警告的代碼是類型安全的,只有在這種情況下才可以用一個@Sup

SuppressWarnings注解可以用在任何粒度的級別中,從單獨的局部變量到整個類都可以。應該始終在盡可能小的范圍中使用SuppressWarnings注解。它通常是個變量聲明,或者是非常簡短的方法或者構造器。永遠不要在整個類上使用SuppressWarnings,這么做可能會掩蓋了重要的警告。

總而言之,非受檢警告很重要,不要忽略它們。每一條警告都表示可能在運行時拋出ClassCastException異常。要盡最大的努力消除這些警告。如果無法消掉同時確實是類型安全的,就可以在盡可能小的范圍中,用@SuppressWarnings("unchecked")注解來禁止這條警告。要用注釋把禁止該警告的原因記錄下來。

25、 列表優先于數組

數組與泛型相比,有兩個重要的不同點:首先,數組是協變的,如Sub為Super的子類型,那么數組類型Sub[]就是Super[]的子類型。但泛型則是不可變的,對于任意兩個不同的類型Type1和Type2,List<Type1>與List<Type2>沒有任何父子關系。

下面的代碼片段是合法的:

Object[] objectArray = new Long[1];

objectArray[0]= "";//運行時拋異常

但下面這段代碼則在編譯時就不合法:

List<Object> ol = new ArrayList<Long>();//編譯時就不能通過

ol.add("");

利用數組,你會在運行時才可以發現錯誤,而利用列表,則可以在編譯時發現錯誤。而我們最好是編譯時發現錯誤,及早的處理它。

數組與泛型之間的第二大區別在于,數組是具體化的[JLS,4.7]。因此數組會在運行時才知道并檢查它們的元素類型約束。相比,泛型則是通過擦除[JLS,4.6]來實現的。因此泛型只在編譯時強化它們的類型信息,并在運行時丟棄它們的元素類型信息。擦除就是使泛型可以與沒有使用泛型的代碼隨意進行互用。

由于上述這些根本的區另,因此數組和泛型不能很好混合使用。例如,創建泛型、參數化類型或者類型參數的數組是非法的,如:new List<E>[]、new List<String>[]、new E[]都是非法的。

為什么不允許創建泛型數組呢?看具體例子:

List<String>[] stringLists= new List<String>[1];//1

List<Integer> intList = Arrays.asList(42); //2

Object[] objects = stringLists; //3

objects[0] = intList; //4

String s = stringLists[0].get(0); //5

這里首先假設第一行可以,其他行本身編譯是沒有問題的,但運行到5行時肯定會拋出ClassCastException異常。為了防止出現這種情況,創建泛型數組第1行就不允許了。

從技術角度說,像List<Strign>、List<E>、E這樣的類型應稱作為不可具體化的類型[JLS,4.7]。直觀地說,不可具體化的類型是指其運行時表示法包含的信息比它的編譯時表示法包含的信息更少的類型。唯一可具體化的參數化類型是無限制的符類型,如List<?>和Map<?,?>(Map<?,?>[]maps=newMap<?,?>[1];),雖然不常用,但是創建無限制通配類型的數組是合法。

當你得到泛型數組創建錯誤時,最好的解決辦法通常是優先使用集合類型List<E>,而不是E[]。這樣可以會損失一些性能或者簡潔性,但是挽回的是更高的類型安全性和互用性。

總之,數組和泛型有著非常不同的類型規則。數組是協變且可以具體化的,泛型是不可變的且可以被擦除的。因此,數組提供了運行時的類型安全,但是沒有編譯時的類型安全,反之,對于泛型也一樣。一般來說,數組和泛型不能很好地混合使用。如果你發現自己將它們混合起來使用,并且得到了編譯時錯誤或者警告,你的第一反應就應該是用列表來代替數組。

26、 優先考慮泛型

考慮第6條中的堆棧實現,將它定義成泛型類。第一種是將elements定義成類型參數數組:

publicclassStack<E> {

privateE[] elements;//定義成類型參數數組

privateintsize = 0;

privatestaticfinalintDEFAULT_INITIAL_CAPACITY= 16;

//通過pust(E)我們只能將E類型的實例放入到elements中,這已充分確保類型

//安全,所以這里可以強轉。但是運行時數組的類型不是E[],它仍然是Objct[]類型的!

@SuppressWarnings("unchecked")

publicStack() {

//elements =new E[DEFAULT_INITIAL_CAPACITY];//不能創建類型參數數組

/*

*編譯器不可能證明你的程序是類型安全的,但是你可以證明。你自己必須確保未受

*檢的轉換不會危及到程序的類型安全。因為elements保存在一個私有的域中,永遠

*不會返回到客戶端。或者傳給任何其他方法。這個數組中保存的唯一元素,是傳給

* push方法的那些元素,它們的類型為E,因此未受檢的轉換不會有任何危害。一旦

*你證明了未受檢的轉換是安全的,就要在盡可能小的范圍中禁警告。然后你就可以

*使用的它了,無需顯示轉換,也不需擔心會出ClassCastException異常。

*/

elements = (E[])newObject[DEFAULT_INITIAL_CAPACITY];//這里會有

}

publicvoidpush(E e) {

ensureCapacity();

elements[size++] = e;

}

publicE pop() {

if(size == 0)

thrownewEmptyStackException();

E result = elements[--size];

Word-spacing: 0px; text-transfo

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 龙南县| 开鲁县| 甘南县| 临夏市| 双江| 平乡县| 镇巴县| 靖西县| 云龙县| 汝阳县| 漠河县| 镇远县| 新民市| 松阳县| 南川市| 龙陵县| 曲松县| 鲜城| 闵行区| 合川市| 青川县| 碌曲县| 特克斯县| 叶城县| 甘洛县| 山阴县| 石嘴山市| 嘉义市| 福清市| 且末县| 岳阳县| 兴国县| 新竹市| 德江县| 肇东市| 金寨县| 东山县| 黑河市| 莎车县| 洛宁县| 股票|