《Java編程思想》第四版讀書筆記 第十一章 持有對象

11.1java

在第一個例子中使用了@SuppressWarnings註解。它的做用是抑制編譯器產生的告警信息。設計模式

(1)用於抑制一個類型的警告:數組

@SuppressWarnings("unchecked")函數

(2)用於抑制多個類型的警告:測試

@SuppressWarnings(value = {"unchecked", "rawtypes"})優化

(3)用於抑制多有類型的警告:編碼

@SuppressWarnings("all")spa

該註解目標爲類、字段、函數、函數形參、構造函數和函數的局部變量。建議註解聲明在最接近告警發生的位置。操作系統

javac -Xlint 用於在編譯程序的過程當中進行更細節的額外檢查。翻譯

javac帶有-X表示非標準選項(不帶-X天然是標準選項了),表示當前版本支持,將來不必定支持的選項。經過javac -X可查看當前版本支持的非標準選項。

11.2

Java 容器劃分紅兩個不一樣的概念:

(1)Collection。一個獨立元素的序列,這些元素都服從一些規則。例如,List必須按順序插入,Set不能有重複的元素,Queue是隊列;

(2)Map。一組鍵值對對象,容許使用鍵來查找值。

11.3

本小節主要介紹了四種獲得列表的方法:

(1)Collection的構造函數能夠接受另外一個Collection對象,用它來初始化自身;

(2)Arrays.asList()方法的參數能夠是數組或變長參數,返回的是List對象,可是在這種狀況下,其底層表示的是數組,所以不能調整尺寸,當調用它的add()方法和remove()(此處書中寫的是delete()方法,應該是筆誤)方法時會拋出Unsupported Operation異常;

(3)Collections.addAll()方法的參數是一個Collection對象、數組或變長參數,將元素添加到Collection對象中;

(4)Collection.addAll()(注意這裏是Collection不是Collections)只能接口另外一個Collection對象做爲參數,這種方法不如(2)和(3)靈活,可是這種方法速度很快,當複合條件時它爲首選。

本小節的最後,做者舉例說明了Arrays.asList()可能會遇到的問題和解決的方法。當將Light和Heavy類型的對象做爲參數傳入Arrays.asList()方法中時,編譯器會認爲方法返回的類型是List,將其賦值給一個List的引用就會報錯,解決方法是給Arrays.asList()方法添加顯示類型Arrays.asList()。

通過編碼測試這個問題在1.8中獲得瞭解決,可是1.7以前的版本依舊存在這個問題。

11.4

若是想要打印數組的內容,必須將其做爲參數傳遞給Arrrays.toString()方法,可是容器不須要相似的幫助,它的toString()直接能夠打印出容器的內容。

Collection容器主要包括:

(1)List,它以特定的順序保存一組元素。ArrayList和LinkedList是List的兩個主要類型。ArrayList長於隨機訪問元素,可是在中間插入和移除元素較慢。LinkedList優化了順序訪問,而且在List中間進行插入和刪除操做代價較低,可是隨機訪問較慢,而且它的特性比ArrayList更大。

(2)Set,它的元素不能重複。HashSet、TreeSet和LinkedHashSet是主要的Set類型。經過將它們的內容打印出來能夠看出,它們實現存儲元素的方式不一樣。HashSet使用較複雜的存儲方法以提供最快的獲取元素方式;TreeSet按照比較結果的升序保存對象;LinkedHashSet按照添加的順序保存對象。

(3)Queue,它只容許在一端插入對象,在另外一端移除對象。

HashMap、TreeMap和LinkedHashMap是Map的三種主要類型,主要區別於 HashSet、TreeSet和LinkedHashSet相同。

11.5

例子中總結了一些List的方法:

可使用contains()方法來肯定某個對象是否在列表中,若是想移除一個對象,則能夠將這個對象的引用傳遞給remove()方法,無此對象會致使刪除失敗,方法返回false。若是有一個對象的引用,可使用indexOf()方法來發現對象在List中的索引號,無此對象返回-1。

注意:肯定一個元素是否屬於List、發現某個元素的索引以及從List中移除一個元素,會用到equals()方法。因此List的這些行爲會根據持有對象的equals()行爲不一樣有所變化。也可使用索引來移除List中的一個元素,這樣就不用擔憂equals()方法。

能夠在List中間插入,ArrayList中間插入是很昂貴的,而LinkedList中間插入是很廉價的。

containsAll()判斷不在意順序。

shuffle()方法的做用是隨機打亂原來的元素順序(洗牌)。

retainAll()僅在List中保留指定collection中所包含的元素。

set()方法替換掉指定索引位置的元素。

addAll()不指定位置將添加到list最後,若是指定位置能夠插入到List中間。

toArray()方法將Collection轉換爲數組。無參數版本返回的是Object數組,有參數的版本能夠向其傳遞目標類型的數組,那麼它將產生指定類型的數組(而不是Object數組)。若是參數數組過小,存放不下目標類型的數據,那麼它將建立合適尺寸的數組。

11.6

迭代器一般被稱爲輕量級對象,建立它的代價很是小。

Iterator的做用(它只能單向移動):

(1)使用容器的iterator()方法要求容器返回一個Iterator。Iterator將準備好返回序列的第一個元素;

(2)使用next()得到序列中的下一個元素;

(3)使用hasNext()檢測序列中是否還有元素;

(4)使用remove()將迭代器新近返回的元素刪除。這裏須要注意,迭代器真的能夠刪除容器裏的元素,可是注意調用remove()以前必須調用next()方法。remove()方法是一個可選的方法,即不是全部的Iterator實現都必須實現該方法。(爲何它是可選的?我看API remove()方法若是迭代器不支持 remove 操做會拋出 UnsupportedOperationException  。

迭代器實際上是一種設計模式,使用它能夠沒必要知道容器的確切類型。這樣就可以將遍歷序列的操做與序列底層的結構分離

ListIterator是Iterator的子類型,它更強大,可是它只能用於各類List類的訪問。它能夠雙向移動。

nextIndex()對 next 的後續調用所返回元素的索引。(若是列表迭代器在列表的結尾,則返回列表的大小);

previousIndex()返回對 previous 的後續調用所返回元素的索引。(若是列表迭代器在列表的開始,則返回 -1);

可使用set()方法替換訪問過的最後一個元素;

調用listIterator()方法產生一個指向List開始處的ListIterator,也能夠調用listIterator(int n)方法建立一個開始就指向 索引爲n的元素處的ListIterator。

11.7

LinkedList在實現了基本的List接口的功能之上還添加了可使其用做棧、隊列或雙端隊列的方法。

有些方法並無差異、有些只有細微的差異,它們有不一樣的名字主要是由於這些名字在特定的環境中更加 合適。例如:

getFirst()、element()和peek()都返回列表的第一個元素且不刪除它們,若是列表爲空前兩個方法會拋出NoSuchElmentException,peek()方法則會返回null;

removeFirst()、remove()和poll()方法都是移除並返回列表的頭,若是列表爲空前兩個會拋出NoSuchElementException,poll()方法會返回null;

addFirst()與add()和addLast()相同,都將某個元素 插入到列表的尾部;

removeLast()移除並返回列表的最後一個元素;

offer()將指定元素添加的列表的末尾。

練習13上一段有句話翻譯有誤,原話爲「若是你瀏覽一下Queue接口就會發現,它在LinkedList的基礎上添加了element()、offer()、peek()、poll()和remove()方法,以使其能夠成爲一個Queue的實現。」翻了一下英文版,認爲應該翻譯爲:「若是你瀏覽一下Queue接口就會發現,element()、offer()、peek()、poll()和remove()方法被添加到LinkedList類中使其成爲一個Queue接口的實現。

11.8

做者使用代理用LinkedList實現了一個棧,這裏使用代理而不是繼承LinkedList是由於LinkedList還有許多與棧無關的方法,使用代理能夠屏蔽掉。一個棧須要的方法主要有push(T t)入棧、poll()出棧和peek()返回棧頂元素但不刪除,另外還須要有一個empty()方法判斷棧是否爲空。

Java在早期版本中就已經有了棧java.util.Stack,可是因爲設計糟糕,如今已經不推薦使用了,還有Vector、Dictionary等。

11.9

TreeSet的構造函數容許傳入一個比較器(Comparator) 做爲參數用於給元素排序

在最後一個例子中做者爲字符串不區分大小寫排序傳入了String.CASE_INSENSITIVE_ORDER比較器。

11.10

對象能夠返回它的鍵的Set——keySet(),返回值的Collection——values(),返回鍵值對的Set——entrySet()。

11.11

若是想使用隊列,能夠建立LinkedList對象並向上轉型爲Queue,這樣Queue接口窄化了LinkedList的訪問權限。

offer()方法在容許的狀況下將元素插入到隊尾,peek()和element()在不刪除元素的狀況下返回隊頭,若是隊列爲空前者返回Null,然後者拋出NoSuchElementException異常。poll()和remove()方法返回隊頭並刪除元素,隊列爲空時前者返回Null,後者拋出異常。

Java 1.5添加了PriorityQueue類,在這個隊列中,不是根據插入的時間來彈出元素,而是根據元素的優先級,優先級高的先彈出。當用offer()向PriorityQueue插入對象後,它會在隊列中根據天然順序進行排序,能夠向PriorityQueue傳入自定義的Comparator來改變默認的順序。

練習29讓咱們建立一個繼承自Object的類,而後把這個類的實例添加到PriorityQueue隊列中,這樣會拋出異常,由於這個類沒有實現Comparable接口,PriorityQueue沒有辦法判斷元素的優先級。

11.12

首先介紹了AbstractCollection抽象類,它實現了Collection接口,只有iterator()和size()方法是抽象方法,繼承時須要實現。另外須要注意的是AbstractCollection的add()方法雖然被實現了,可是函數裏僅有一句代碼——拋出UnSupportedOperationException異常。因此繼承AbstractCollection時還要覆蓋add()方法。

11.13

Java 1.5添加了Iterable接口,它的iterator()方法返回一個迭代器,注意到Collection接口也繼承了Iterable接口。實現Iterable接口的類均可以應用在foreach語句中,同時數組也能夠應用於foreach語句,可是注意數組並無實現Iterable接口。

System.getEnv()方法返回操做系統的環境變量。

例子中使用了設計模式中的適配器模式,它的主要功能是將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠在一塊兒工做。

例子中着重提到了Arrays.asList()方法,若是修改方法返回的List,那麼做爲參數傳入的數組也將會被修改,此種狀況容易被忽略。

11.14

新程序中不該該再使用已通過時的Vector、Hashtable和Stack。

下圖是容器相關的接口和類之間的關係:

總結起來共有四種容器:List、Set、Queue和Map。每一種各有兩三個實現。經常使用的在圖中用粗線框表示,虛線框表示接口,實線框表示類。空心虛線箭頭接口或者類實現了上層接口,實心虛線箭頭表示某個類能夠生成箭頭所指向的類。

相關文章
相關標籤/搜索