1. 程式人生 > >第9章 集合(重中之重)

第9章 集合(重中之重)

1、java迭代器:

public interface Iterator < E >
{
	E next ( ) ;
	boolean hasNextO ;
	void remove 0 ;
	default void forEachRemaining ( Consumer < ? super E > action ) ;
}

樣例程式:

Collection < String > c = . . . ;
Iterator < String > iter = c.iterator();
while ( iter.hasNext())
{
	String element = iter.next();
   do something with element
}

用 “ foreach ” 迴圈可以更加簡練地表示同樣的迴圈操作 :

for ( String element : c )
{
	do something with element
}

2、 Iterable 介面:
編譯器簡單地將 “ for each ” 迴圈翻譯為帶有迭代器的迴圈 。
“for each ” 迴圈可以與任何實現了 Iterable 介面的物件一起工作 , 這個介面只包含一個
抽象方法 :

public interface Iterable < E >{
	Iterator < E > iterator() ;
}

Collection 介面擴充套件了 Iterable 介面。 因此 , 對於標準類庫中的任何集合都可以使用 “
for each ” 迴圈 。

3、java集合類庫的迭代器與c++STL迭代器區別:
Java 集合類庫中的迭代器與其他類庫中的迭代器在概念上有著重要的區別。 在傳統的集合類庫中,例如 , C + + 的標準模版庫 , 迭代器是根據陣列索引建模的 。 如果給定這樣一個迭代器 ,就可以檢視指定位置上的元素 , 就像知道陣列索引 i 就可以査看陣列元素 a [ i ] — 樣 。不需要查詢元素, 就可以將迭代器向前移動一個位置 。 這與不需要執行査找操作就可以通過i + + 將陣列索引向前移動一樣 。 但是, Java 迭代器並不是這樣操作的 。 查詢操作與位置變更
是緊密相連的。 查詢一個元素的唯一方法是呼叫 next ,而在執行查詢操作的同時, 迭代器的位置隨之向前移動。因此, 應該將 Java 迭代器認為是位於兩個元素之間 。 當呼叫 next 時 , 迭代器就越過下一個元素 , 並返回剛剛越過的那個元素的引用。

4、next 方法和 remove 方法的呼叫具有互相依賴性:
如果呼叫
remove 之前
沒有呼叫 next 將是不合法的 。 如果這樣做 , 將會丟擲一個 IllegalStateException 異常

如果想刪除兩個相鄰的元素 , 不能直接地這樣呼叫 :
it . remove ( ) ;
it . remove ( ) ; / / Error !
相反地, 必須先呼叫 next 越過將要刪除的元素 。
it , remove ( ) ;
it . next ( ) ;
it . remove ( ) ; / / OK

5、**在 Java 類庫中, 集合類的基本介面是 Collection 介面 。**下面列出 Collection 介面常用的API:
java . util . Collection < E > 1.2
• Iterator < E > iterator ()
返回一個用於訪問集合中每個元素的迭代器 。
•int size ()
返回當前儲存在集合中的元素個數。
•boolean isEmpty ()
如果集合中沒有元素 , 返回 true。
•boolean contains ( Object obj )
如果集合中包含了一個與 obj 相等的物件 , 返回 true。
•boolean containsAll ( Collection < ? > other )
如果這個集合包含 other 集合中的所有元素 , 返回 true。
•boolean add ( Object element )
將一個元素新增到集合中。 如果由於這個呼叫改變了集合 , 返回true 。
•boolean addAll ( Collection < ? extends E > other )
將 other 集合中的所有元素新增到這個集合。 如果由於這個呼叫改變了集合 , 返回true。
•boolean remove ( Object obj )從這個集合中刪除等於 obj 的物件。 如果有匹配的物件被刪除 , 返回true。
•boolean removeAll ( Collection < ? > other )
從這個集合中刪除 other 集合中存在的所有元素。 如果由於這個呼叫改變了集合 , 返回 true 。
•default boolean removelf ( Predicate < ? super E > filter ) 8
從這個集合刪除 filter 返回 true 的所有元素。 如果由於這個呼叫改變了集合 , 則返回 true 。
•void clear ( )
從這個集合中刪除所有的元素 。
•boolean retainAll( Collection < ? > other )
從這個集合中刪除所有與 other 集合中的元素不同的元素 。 如果由於這個呼叫改變了
集合 , 返回 true。
•Object [] toArray ( )
返回這個集合的物件陣列。
•< T > T [] toArray ( T [] arrayToFill )
返回這個集合的物件陣列。 如果 arrayToFill足夠大, 就將集合中的元素填入這個陣列
中。 剩餘空間填補null ; 否則 , 分配一個新陣列 , 其成員型別與 arrayToFill 的成員類
型相同 , 其長度等於集合的大小 , 並填充集合元素 。

6、泛形要求能包容的是物件型別,而基本型別在java裡不屬於物件。
但是基本型別都有其包裝型別,也就是物件型別: int->Integer long->Long …

7、集合兩大基本介面: Collection 和 Map。

8、java集合框架下具體的常用匯總:

ArrayList                    一種可以動態增長和縮減的索引序列
LinkedList                   一種可以在任何位置進行高效地插人和刪除操作的有序序列
ArrayDeque                   一種用迴圈陣列實現的雙端佇列
HashSet                      一種沒有重複元素的無序集合
TreeSet                      一種有序集
EnumSet                      一種包含列舉型別值的集
LinkedHashSet                一種可以記住元素插人次序的集
PriorityQueue                一種允許高效刪除最小元素的集合
HashMap                      一種儲存鍵 / 值關聯的資料結構
TreeMap                      一種鍵值有序排列的對映表
EnumMap						 一種鍵值屬於列舉型別的對映表
LinkedHashMap                一種可以記住鍵 / 值項新增次序的對映表
WeakHashMap                  一種其值無用武之地後可以被垃圾回收器回收的對映表
IdentityHashMap              一種用 = 而不是用 equals 比較鍵值的對映表

9、有序集合支援順序隨機兩種訪問方式的List介面
java.util.List 1.2

•ListIterator < E > 1 istIterator ( )
返回一個列表迭代器, 以便用來訪問列表中的元素 。
•ListIterator < E > 1 istIterator ( int index )
返回一個列表迭代器 , 以便用來訪問列表中的元素 , 這個元素是第一次呼叫 next 返回的給定索引的元素。
•void add ( int i , E element )
在給定位置新增一個元素 。
•void addAl 1 ( int i , Col 1 ection < ? extends E > elements )
將某個集合中的所有元素新增到給定位置。
•E remove ( int i )
刪除給定位置的元素並返回這個元素。
•E get ( int i )
獲取給定位置的元素。
•E set ( int i , E element )
用新元素取代給定位置的元素 , 並返回原來那個元素 。
•int indexOf ( Object element )
返回與指定元素相等的元素在列表中第一次出現的位置 , 如果沒有這樣的元素將返回 - 1。
•int 1 astlndexOf ( Object element )
返回與指定元素相等的元素在列表中最後一次出現的位置 , 如果沒有這樣的元素將返
回 - 1.

10、實現了List介面的連結串列相關API:
java . util . Listlterator < E > 1.2

•void add ( E newElement )
在當前位置前新增一個元素。
•void set ( E newElement )
用新元素取代 next 或 previous 上次訪問的元素。 如果在next 或 previous 上次呼叫之後列表結構被修改了, 將丟擲一個IllegalStateException 異常。
•boolean hasPrevious ()
當反向迭代列表時, 還有可供訪問的元素 , 返回true 。
•E previous ( )
返回前物件。 如果已經到達了列表的頭部 ,就丟擲一個NoSuchElementException 異常。
•int nextlndex ()
返回下一次呼叫 next 方法時將返回的元素索引 。
•int previousIndex ( )
返回下一次呼叫 previous 方法時將返回的元素索引。

java.util.LinkedList 1.2

•LinkedList ()
構造一個空連結串列。
• LinkedList( Collection < ? extends E > elements )
構造一個連結串列 , 並將集合中所有的元素新增到這個連結串列中。
•void addFirst ( E element )
•void addLast ( E element )
將某個元素新增到列表的頭部或尾部。
•E getFirst ( )
•E getLast ( )
返回列表頭部或尾部的元素 。
•E removeFirst ( )
•E removeLast ( )
刪除並返回列表頭部或尾部的元素 。

11、動態陣列ArrayList,重點記憶其也實現了List介面。
註釋 : 對於一個經驗豐富的 Java 程式設計師來說 , 在需要動態陣列時 , 可能會使用 Vector 類。
為什麼要用 ArrayList 取代 Vector 呢 ? 原因很簡單 : Vector 類的所有方法都是同步的。可以由兩個執行緒安全地訪問一個 Vector 物件。 但是 , 如果由一個執行緒訪問Vector , 程式碼要在同步操作上耗費大量的時間。 這種情況還是很常見的 。而 ArrayList 方法不是同步的,因此, 建議在不需要同步時使用ArrayList , 而不要使用 Vector。

12、雜湊集合hashset相關API:
java . util . HashSet < E > 1.2

•HashSet ( )
構造一個空散列表 。
•HashSet ( Col 1 ection < ? extends E > elements )
構造一個雜湊集 , 並將集合中的所有元素新增到這個雜湊集中 。
•HashSet ( int initialCapacity )
構造一個空的具有指定容量 ( 桶數 ) 的雜湊集 。
•HashSet ( int initialCapacity , float loadFactor )
構造一個具有指定容量和裝填因子 ( 一個 0.0 ~ 1.0 之間的數值 , 確定散列表填充的百分比
, 當大於這個百分比時 , 散列表進行再雜湊 ) 的空雜湊集 。

java . Iang . Object 1.0

•int hashCode ( )//注意這是Object物件自帶的雜湊碼生成方法,大多數與物件的儲存地址有關
返回這個物件的雜湊碼。 雜湊碼可以是任何整數 , 包括正數或負數 。 equals 和 hashCode的定義必須相容, 即如果 x . equals ( y ) 為 true ,x . hashCodeO 必須等於 y . hashCodeO。

13、樹集TreeSet,自己習慣的c++STl中的set,是一種基於進階二叉搜尋樹(紅黑樹)的集合。所有內部元素成功新增之後都會自動排好序。但是作為代價是,將一個元素新增到樹中要比新增到散列表中慢 ,如果樹中包含n 個元素 , 査找新元素的正確位置平均需要 l 0 g 2 n 次比較。 例如 ,如果一棵樹包含了 1000 個元素, 新增一個新元素大約需要比較10 次。

14、 註釋 : 要使用樹集 , 必須能夠比較元素 。 這些元素必須實現 Comparable 介面 ( 參見6.1 . 1節 ), 或者構造集時必須提供一個 Comparator( 參見 6.2 . 2 節和 6.3 . 8 節 )。

15、關於TreeSet與HashSet選擇問題:
是否總是應該用樹集取代雜湊集 。 畢竟 , 新增一個元素所花費的時間看上去並不很長, 而且元素是自動排序的 。 到底應該怎樣做將取決於所要收集的資料。 如果不需要對資料進行排序 ,就沒有必要付出排序的開銷。 更重要的是 , 對於某些資料來說, 對其排序要比雜湊函式更加困難 。 雜湊函式只是將物件適當地打亂存放 , 而比較卻要精確地判別每個物件。

16、樹集TreeSet相關API:
java . util . TreeSet 1.2

• TreeSet( )
• TreeSet( Comparator < ? super E > comparator )構造一個空樹集 。
• TreeSet( Collection < ? extends E > elements )
• TreeSet ( SortedSet < E > s )
構造一個樹集 , 並增加一個集合或有序集中的所有元素 ( 對於後一種情況, 要使用同樣的順序 )。

java . util . SortedSet < E > 1.2

•Comparator< ? super E > comparator )
返回用於對元素進行排序的比較器。 如果元素用 Comparable 介面的 compareTo 方法進行比較則返回 null。
•E first()
•E last()
返回有序集中的最小元素或最大元素。

java . util . NavigableSet < E > 6

•E higher ( E value )
•E lower ( E value )
返回大於 value 的最小元素或小於 value 的最大元素, 如果沒有這樣的元素則返回 null 。
• E ceiling ( E value )
•E floor ( E value )
返回大於等於 vaiue 的最小元素或小於等於 value 的最大元素, 如果沒有這樣的元素則返回 null。
•E pollFirst ( )
•E pollLast
刪除並返回這個集中的最大元素或最小元素 , 這個集為空時返回 null 。
• Iterator < E >descendingIterator()
返回一個按照遞減順序遍歷集中元素的迭代器。

17、雙端佇列及相關API:
在Java SE 6 中引人了 Deque 介面 , 並由 ArrayDeque 和LinkedList 類實現。 這兩個類都提供了雙端佇列 , 而且在必要時可以增加佇列的長度 。
java . utii . Queue < E > 5.0

•boolean add ( E element )
•boolean offer ( E element )
如果佇列沒有滿, 將給定的元素新增到這個雙端佇列的尾部並返回 true 。 如果佇列滿
了, 第一個方法將丟擲一個 IllegalStateException ,而第二個方法返回 false。
•E remove ( )
•E poll ( )
假如佇列不空, 刪除並返回這個佇列頭部的元素。如果佇列是空的 , 第一個方法丟擲NoSuchElementException , 
而第二個方法返回 null。
•E elementC )
•E peek ( )
如果佇列不空, 返回這個佇列頭部的元素 , 但不刪除 。 如果佇列空 , 第一個方法將拋
出一個 NoSuchElementException , 而第二個方法返回 null。

java . util . Deque < E > 6

•void addFirst ( E element )
•void addLast ( E element )
•boolean offerFirst ( E element )
•boolean offerLast ( E element )
將給定的物件新增到雙端佇列的頭部或尾部。
 如果佇列滿了 , 前面兩個方法將丟擲一個IllegalStateException, 而後面兩個方法返回false。
•E removeFirst ( )
•E removeLast ( )
•E pollFirstO
•E pollLastO
如果佇列不空, 刪除並返回佇列頭部的元素 。 
如果佇列為空 , 前面兩個方法將丟擲一個 NoSuchElementException , 而後面兩個方法返回 null 。
•E getFirstO
•E getLastO
•E peekFirstO
•E peekLast ( )
如果佇列非空, 返回佇列頭部的元素 , 但不刪除 。 如果佇列空 , 前面兩個方法將丟擲
一個 NoSuchElementException , 而後面兩個方法返回 null 。

java . util . ArrayDeque < E > 6

•ArrayDeque ( )
•ArrayDeque ( int initialCapacity )
用初始容量 16 或給定的初始容量構造一個無限雙端佇列。

18、優先佇列:
與 TreeSet一樣, 一個優先順序佇列既可以儲存實現了 Comparable 介面的類物件 , 也可以
儲存在構造器中提供的 Comparator 物件。
java . util . PriorityQueue 5.0

•PriorityQueue ( )
•PriorityQueue ( int initialCapacity )
構造一個用於存放 Comparable 物件的優先順序佇列。
•PriorityQueue ( int initialCapacity , Comparator ? super E > c )
構造一個優先順序佇列 , 並用指定的比較器對元素進行排序。

18、對映:
Java 類庫為對映提供了兩個通用的實現 : HashMap 和 TreeMap。 這兩個類都實現了 Map 介面 。雜湊對映對鍵進行雜湊 , 樹對映用鍵的整體順序對元素進行排序 , 並將其組織成搜尋樹。 雜湊或比較函式只能作用於鍵 。 與鍵關聯的值不能進行雜湊或比較 。應該選擇雜湊對映還是樹對映呢 ? 與集一樣 , 雜湊稍微快一些 , 如果不需要按照排列順序訪問鍵, 就最好選擇雜湊 。

19、要想檢索一個物件, 必須使用 ( 因而 , 必須記住 ) 一個鍵 。
String id = " 987 - 98 - 9996 " ;
e = staff , get ( id ) ; / / gets harry
如果在對映中沒有與給定鍵對應的資訊 , get 將返回 null。
null 返回值可能並不方便 。 有時可以有一個好的預設值 , 用作為對映中不存在的鍵 。 然後使用 getOrDefault 方法。
Map < String , Integer > scores = . .
int score = scores . get ( id , 0 ) ; / / Gets 0 if the id is not present

20、基本對映相關API:
java . util . Map < K, V > 1.2//map介面

•V get ( Object key )
獲取與鍵對應的值 ; 返回與鍵對應的物件 , 如果在對映中沒有這個物件則返回 null。鍵可以為 null。
•default V getOrDefault ( Object key , V defaultValue )
獲得與鍵關聯的值 ; 返回與鍵關聯的物件, 或者如果未在對映中找到這個鍵 , 則返回default Value。
•V put ( K key , V value )
將鍵與對應的值關係插入到對映中。 如果這個鍵已經存在 , 新的物件將取代與這個鍵對應的舊物件。 
這個方法將返回鍵對應的舊值 。 如果這個鍵以前沒有出現過則返回null 。
鍵可以為 null , 但值不能為 null 。
•void putAll ( Map < ? extends K , ? extends V > entries )
將給定對映中的所有條目新增到這個對映中。
•boolean containsKey ( Object key )
如果在對映中已經有這個鍵, 返回true。
•boolean containsValue ( Object value )
如果對映中已經有這個值, 返回true。
• default void forEach ( BiConsumer < ? super K , ? super V > action ) 8
對這個對映中的所有鍵 / 值對應用這個動作。

java . utii . HashMap<K, V> 1.2

•HashMap ( )
•HashMap ( int initialCapacity )
•HashMap ( int initialCapacity , float 1 oadFactor )

用給定的容量和裝填因子構造一個空雜湊對映 ( 裝填因子是一個 0.0 〜 1.0 之間的數值。 這個數值決定散列表填充的百分比 。 一旦到了這個比例 , 就要將其再雜湊到更大的表中 )。 預設的裝填因子是0.75。

java . util . TreeMap < K , V > 1.2

•TreeMap ( )
為實現 Comparable 介面的鍵構造一個空的樹對映。
• TreeMap ( Comparator < ? super K > c )
構造一個樹對映 , 並使用一個指定的比較器對鍵進行排序。
• TreeMap ( Map < ? extends K , ? extends V > entries )
構造一個樹對映 , 並將某個對映中的所有條目新增到樹對映中。
• TreeMap ( SortedMap < ? extends K , ? extends V > entries )
構造一個樹對映 , 將某個有序對映中的所有條目新增到樹對映中, 並使用與給定的有序對映相同的比較器。

java . util . SortedMap < K , V > 1.2

• Comparator <? super K > comparator ( )
返回對鍵進行排序的比較器。 如果鍵是用 Comparable 介面的 compareTo 方法進行比較的, 返回null 。
•K firstKey( )
• K lastKey ( )
返回對映中最小元素和最大元素。

21、更新對映項:
處理對映時的一個難點就是更新對映項。 正常情況下 , 可以得到與一個鍵關聯的原值 ,完成更新, 再放回更新後的值 。 不過 , 必須考慮一個特殊情況 ,即鍵第一次出現。 下面來看
一個例子, 使用一個對映統計一個單詞在檔案中出現的頻度 。 看到一個單詞 ( word )時, 我
們將計數器增 1, 如下所示 :
counts . put ( word , counts . get ( word ) + 1 ) ;
這是可以的, 不過有一種情況除外 : 就是第一次看到word 時。 在這種情況下 , get會返回 null , 因此會出現一個 NullPointerException 異常。
作為一個簡單的補救 , 可以使用 getOrDefault 方法 :
counts , put ( word , counts . getOrDefault ( word , 0 ) + 1 ) ;
另一種方法是首先呼叫 putlfAbsent 方法。 只有當鍵原先存在時才會放入一個值 。
counts . putlf Absent ( word , 0 ) ;
counts . put ( word , counts . get ( word ) + 1 ) ; // Now we know that get will succeed
不過還可以做得更好。 merge 方法可以簡化這個常見的操作 。 如果鍵原先不存在 , 下面的呼叫 :
counts . merge ( word , 1 , Integer : : sum ) ;
將把 word 與 1 關聯 , 否則使用 Integer :: sum 函式組合原值和 1 ( 也就是將原值與 1 求和 )

22、P376 與更新對映相關的API不怎麼太常用,以後遇到的是時候再總結。

23、對映檢視:
初學的時候對java裡的對映檢視的概念很不理解,因為c++STL中集合本身就是容器的一種,可以直接訪問檢視元素。但是在java裡,集合框架不認為對映本身是一個集合。( 其他資料結構框架認為對映是一個鍵 / 值對集合,或者是由鍵索引的值集合。) 不過 , 可以得到對映的檢視 ( View ) — 這是實現了Collection 介面或某個子介面的物件 。
在java中對映有 3 種檢視 : 鍵集 、 值集合 ( 不是一個集 ) 以及鍵 / 值對集 。 鍵和鍵 / 值對可以構成一個集 , 因為對映中一個鍵只能有一個副本 。 下面的方法 :
Set < K > keySet ()
Collection < V > values 0
Set < Map . Entry < K , V » entrySetO
會分別返回這 3 個檢視。( 條目集的元素是實現 Map . Entry 介面的類的物件 。 )需要說明的是 , keySet 不是 HashSet 或 TreeSet , 而是實現了 Set 介面的另外某個類的物件。 Set介面擴充套件了 Collection 介面。 因此 ,可以像使用集合一樣使用 keySet。
需要說明的是 , keySet 不是 HashSet 或 TreeSet , 而是實現了 Set 介面的另外某個類的物件。 Set介面擴充套件了 Collection 介面。 因此 ,可以像使用集合一樣使用 keySet。
例如 , 可以列舉一個對映的所有鍵 :

Set < String > keys = map . keySet();
for ( String key : keys )
{
	 do something with key
}

如果想同時檢視鍵和值, 可以通過列舉條目來避免查詢值 。 使用以下程式碼 :

for ( Map . Entry < String , Employee 〉 entry : staff . entrySetO )
{
	String k = entry . getKeyO ;
 	Employee v = entry . getValueO ;
	do something with k , v
}

提示 : 以上這是原先訪問所有對映條目的最高效的方法。 如今 , 只需要使用
forEach 方法 :

counts . forEach ( ( k , v ) - > {
	do something with k , v
} ) ;

24、對映檢視相關API:
java.util.Map<K, V> 1.2

•Set < Map . Entry < K , V > > entrySet ( )
返回 Map . Entry 物件 ( 對映中的鍵 / 值對 ) 的一個集檢視。 
可以從這個集中刪除元素 ,它們將從對映中刪除, 但是不能增加任何元素 。
• Set < K > keySet ( )
返回對映中所有鍵的一個集檢視 。 
可以從這個集中刪除元素 , 鍵和相關聯的值將從對映中刪除 , 但是不能增加任何元素 。
• Col 1 ection < V >values ()
返回對映中所有值的一個集合檢視。 
可以從這個集合中刪除元素 ,所刪除的值及相應的鍵將從對映中刪除 , 不過不能增加任何元素。

java . util . Map . Entry < K , V > 1.2

• K getKey ()
•V getValueC )
返回這一條目的鍵或值。
•V setValue ( V newValue )
將相關對映中的值改為新值, 並返回原來的值 。

25、弱雜湊對映,連結雜湊映集與對映,列舉集與對映,表示雜湊對映之後找時間再深入研究。

26、重中之重,關於java檢視技術的理解:
用如此多的介面和抽象類來實現數量並不多的具體集合類似乎沒有太大必要。 然而 , 這兩張圖並沒有展示出全部的情況 。 通過使用檢視( views ) 可以獲得其他的實現了 Collection 介面和 Map 介面的物件。 對映類的 keySet 方法就是一個這樣的示例。 初看起來 , 好像這個方法建立了一個新集 , 並將對映中的所有鍵都填進去, 然後返回這個集 。 但是 ,情況並非如此。 取而代之的是 : keySet 方法返回一個實現Set介面的類物件 , 這個類的方法對原對映進行操作。 這種集合稱為檢視 。

27、具體檢視內容,以後找時間深入研究。

28、排序演算法API:
java . util . CoIiections 1.2

• static < T extends Comparable < ? super T » void sort ( List < T > elements )
使用穩定的排序演算法 , 對列表中的元素進行排序。 這個演算法的時間複雜度是 0 ( n log
n ) , 其中 n 為列表的長度。
• static void shuff 1 e ( List < ? > elements )
• static void shuff 1 e ( List < ? > elements , Random r )
隨機地打亂列表中的元素。 這個演算法的時間複雜度是 0 ( n a(n) ) ,
n 是列表的長度 , a ( n )是訪問元素的平均時間。

java . util . List 1.2

• default void sort ( Comparator < ? super T > comparator ) 8
使用給定比較器對列表排序。

java . utii . Comparator < T > 1.2

• static < T extends Comparable < ? super T> > Comparator < T > reverseOrder ( ) 8
生成一個比較器, 將逆置Comparable 介面提供的順序 。
• default Comparator < T > reversed ( ) 8
生成一個比較器 , 將逆置這個比較器提供的順序。

29、二分查詢演算法:
要想查詢某個元素 , 必須提供集合 ( 這個集合要實現 List 介面 , 下面還要更加詳細地介紹這個問題 ) 以及要查詢的元素 。 如果集合沒有采用 Comparable 介面的compareTo 方法進行排序 , 就還要提供一個比較器物件 。

i = Collections . binarySearch ( c , element ) ;
i = Collections . binarySearch ( c , element , comparator ) ;

如果 binarySearch 方法返回的數值大於等於 0 , 則表示匹配物件的索引 。 也就是說 ,c . get ( i ) 等於在這個比較順序下的 element 。 如果返回負值 , 則表示沒有匹配的兀素 。 但是 ,可以利用返回值計算應該將 element 插人到集合的哪個位置 , 以保持集合的有序性 。 插人的
位置是insertionPoint = - i - 1 ;這並不是簡單的 - i, 因為 0 值是不確定的 。 也就是說 , 下面這個操作 :

if ( i < 0 )
c . add ( - i - 1 , element ) ;

將把元素插人到正確的位置上。

30、二分查詢只能對支援隨機訪問的陣列有用:
只有採用隨機訪問, 二分査找才有意義 。 如果必須利用迭代方式一次次地遍歷連結串列的一半元素來找到中間位置的元素, 二分査找就完全失去了優勢 。 因此 , 如果為 binarySearch 演算法提供一個連結串列 , 它將自動地變為線性查詢。

31、 Collections 類常用演算法API合集:

java . util . Collections 1.2
•static < T extends Comparable < ? super T > > T min ( Collection < T > elements )
•static < T extends Comparable < ? super T > > T max ( Col 1 ection < T > elements )
•static < T > min ( Col 1 ection < T > elements , Comparator ? super T > c )
•static < T > max ( Col 1 ection < T > elements , Comparator ? super T > c )
返回集合中最小的或最大的元素 ( 為清楚起見, 引數的邊界被簡化了 ) 。
•static < T > void copy ( List < ? super T > to , List < T > from )
將原列表中的所有元素複製到目辱列表的相應位 1上。 目標列表的長度至少與原列表一樣 。
•static < T > void fill ( List < ? super T > l , T value )
將列表中所有位置設定為相同的值。
•static < T > boolean addAll ( Collection < ? super T > c , T . . . values ) 5.0
將所有的值新增到集合中。 如果集合改變了 , 則返回true。
•static < T > boolean replaceAll ( List < T > l , T oldValue , T newValue ) 1.4
用 newValue 取代所有值為 oldValue 的元素 。
•static int indexOfSubList ( List < ? > l , List < ? > s ) 1.4
•static int 1 astlndexOfSubList ( List < ? > l , List < ? > s ) 1.4
返回 1 中第一個或最後一個等於 S 子列表的索引 。 如果 1 中不存在等於 S 的子列表 , 則
返回 - 1。 例如 , 1 為 [ s , t , a , r ], s 為 [ t , a , r ] , 兩個方法都將返回索引 1。
•static void swap ( List < ? > l , int i , int j ) 1.4
交換給定偏移量的兩個元素。
• static void reverse ( List < ? > l )
逆置列表中元素的順序。 例如 , 逆置列表 [ t , a , r ]後將得到列表 [ r , a , t ]。 這個方法的時
間複雜度為 O ( n ), n為列表的長度。
•static void rotate ( List < ? > l , int d ) 1.4
旋轉列表中的元素 , 將索引 i 的條目移動到位置 ( i + d ) % l . size ( ) 0 例如 , 將列表 [ t, a ,
r ] 旋轉移 2 個位置後得到 [ a , r, t ] 。 這個方法的時間複雜度為 O ( n ) ,n 為列表的長度。
•static int frequency ( Collection < ? > c , Object o ) 5.0
返回 c 中與物件 o 相同的元素個數。
•boolean disjoint ( Collection < ? > cl , Collection < ? > c 2 ) 5.0
如果兩個集合沒有共同的元素 , 則返回 true。

32、重點:傳統陣列與集合之間的轉換
如果需要把一個數組轉換為集合, Arrays . asList 包裝器可以達到這個目的 。 例如 :

String [ ] values = . .
HashSet < String > staff = new HashSet<> ( Arrays . asList ( values )) ;

從集合得到陣列會更困難一些。 當然 , 可以使用 toArray 方法 :

Object [ ] values = staff . toArray() ;

不過, 這樣做的結果是一個物件陣列 。 儘管你知道集合中包含一個特定型別的物件 , 但不能使用強制型別轉換 :

String[ ] values = ( String[ ]) staff . toArray 0 ; / / Error !

toArray 方法返回的陣列是一個 Object [ ] 陣列 , 不能改變它的型別。 實際上 , 必須使用
toArray 方法的一個變體形式, 提供一個所需型別而且長度為 0 的陣列 。 這樣一來 , 返回的陣列就會建立為相同的陣列型別 :

String [ ] values = staff . toArray ( new StringtO ] ) ;

如果願意, 可以構造一個指定大小的陣列 :

staff . toArray ( new String [ staff . size ( ) ] ) ;

在這種情況下, 不會建立新陣列 。
註釋 : 你可能奇怪為什麼不能直接將一個 Class 物件 ( 如 String . class ) 傳遞到 to Array 方法。 原因是這個方法有 “雙重職責 ” , 不僅要填充一個已有的陣列 ( 如果它足夠長 ), 還要建立一個新陣列。

33、棧:

 java . util . Stack < E > 1.0
•E push ( E item )
將 item 壓人桟並返回 item。
•E pop ()
彈出並返回棧頂的 item。 如果棧為空 , 請不要呼叫這個方法 。
•E peek ()
返回棧頂元素, 但不彈出 。 如果棧為空 , 請不要呼叫這個方法 。

34、9.6遺留的集合其他部分以後找時間深入研究。