1. 程式人生 > >JAVA集合類——難得的總結

JAVA集合類——難得的總結

小結:
集合是一個儲存其他物件的物件
Collection介面除了實現對映的集合類之外的所有集合類定義了一些方法
List集合型別描述了一種按位置儲存資料的物件,有序的。
ArrayList是一種在記憶體連續區域 中儲存資料的通用陣列

編碼習慣:
面向介面的程式設計,儘可能降低程式碼變化率:
List<T> lst = new ArrayList<T>();
儘量避免建立不必要的物件:vo應在if判斷成立時建立
TaskReportVO reportvos = new TaskReportVO();
if(i > 0){
lstAllVos.add(reportvos); }
儘量避免同時遍歷和刪除集合。因為這會改變集合的大小;
for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
ComType com = iter.next();
if ( !com.getName().contains("abc")){
ComList.remove(com);}
}

推薦:
for( Iterator<ComType> iter = ComList.iterator(); iter.hasNext();){
ComType com = iter.next();
if ( !com.getName().contains("abc")){
iter.remove(com); }

預估集合內持有物件的大小,不能持有大量物件,佔據記憶體:
List<T> lst = new ArrayList<T>();
無限制的在lst中add element,勢必會造成lst佔用記憶體過高。造成記憶體溢位

Map介面:
集合框架的第二類介面樹。
它提供了一組鍵值的對映。其中儲存的每個物件都有一個相應的關鍵字(key),關鍵字決定了物件在Map中的儲存位置。
關鍵字應該是唯一的,每個key 只能對映一個value。
常用方法:
Object put(Object key,Object value):用來存放一個鍵-值對Map中
Object remove(Object key):根據key(鍵),移除鍵-值對,並將值返回
void putAll(Map mapping) :將另外一個Map中的元素存入當前的Map中
void clear() :清空當前Map中的元素
Object get(Object key) :根據key(鍵)取得對應的值
boolean containsKey(Object key) :判斷Map中是否存在某鍵(key)
boolean containsValue(Object value):判斷Map中是否存在某值(value)
public Set keySet() :返回所有的鍵(key),並使用Set容器存放
public Collection values() :返回所有的值(Value),並使用Collection存放
public Set entrySet() :返回一個實現 Map.Entry 介面的元素 Set

HashMap:
Map 主要用於儲存鍵(key)值(value)對,根據鍵得到值,因此鍵不允許重複,但允許值重複。
HashMap 是一個最常用的Map,它根據鍵的HashCode 值儲存資料,根據鍵可以直接獲取它的值,具有很快的訪問速度。
HashMap最多隻允許一條記錄的鍵為Null;允許多條記錄的值為 Null;
HashMap不支援執行緒的同步,即任一時刻可以有多個執行緒同時寫HashMap;可能會導致資料的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力。

HashMap實現原理---雜湊
Hash雜湊演算法的意義在於提供了一種快速存取資料的方法,它用一種演算法建立鍵值與真實值之間的對應關係。散列表又稱為雜湊表。散列表演算法的基本思想是:以結點的關鍵字為自變數,通過一定的函式關係(雜湊函式)計算出對應的函式值,以這個值作為該結點儲存在散列表中地址。
當散列表中的元素存放太滿,就必須進行再雜湊,將產生一個新的散列表,所有元素存放到新的散列表中,原先的散列表將被刪除。在Java語言中,通過負載因子(load factor)來決定何時對散列表進行再雜湊。例如:如果負載因子0.75,當散列表中已經有75%位置已經放滿,那麼將進行再雜湊。
負載因子越高(越接近1.0),記憶體的使用效率越高,元素的尋找時間越長。負載因子越低(越接近0.0),元素的尋找時間越短,記憶體浪費越多。

何時需重寫equals?
當一個類有自己特有的“邏輯相等”概念(不同於物件身份的概念);
Object類僅僅提供了一個對引用的比較,如果兩個引用不是同一個那就返回false,這是無法滿足大多數物件比較的需要的,所以要覆蓋;
使用==操作符檢查實參是否為指向物件的引用”
使用instanceof操作符檢查實參是否為正確的型別
把實參轉換到正確的型別;
對於該類中每一個“關鍵”域,檢查實參中的域與當前物件中對應的域值是否匹 配。對於既不是float也不是double型別的基本型別的域,可以使用==操作符 進行比較;對於物件引用型別的域,可以遞迴地呼叫所引用的物件的equals方法,對於float和double型別的域,先轉換成int或long型別的值,然後使用==操作符比較;
當你編寫完成了equals方法之後,應該問自己三個問題:它是否是對稱的、傳 遞的、一致的? 如果答案是否定的,那麼請找到 這些特性未能滿足的原因,再修改equals方法的程式碼

equals()和hashCode()同時覆寫
尤其強調當一個物件被當作鍵值(或索引)來使用的時候要重寫這兩個方法;
覆寫equals後,兩個不同例項可能在邏輯上相等,但是根據Object.hashCode方法卻產生不同的雜湊碼,違反“相等的物件必須具有相等的雜湊碼”。
導致,當你用其中的一個作為鍵儲存到hashMap、hasoTable或hashSet中,再以“相等的”找另 一個作為鍵值去查詢他們的時候,則根本找不到
不同型別的hashCode取值
如果該域是布林型的,計算(f?0:1)
如果是char,short,byte或int,計算(int)f
如果是long型別,計算(int)(f^(f>>>32))
如果是float型別,計算Float.floatToIntBits(f)
如果是double型別,計算Dobule.doubleToLongBits(f)
如果該域是一個物件引用,遞迴呼叫hashCode
如果該域是一個數組,則把每個元素當做單獨的域來處理,對每個重要的元素計算一個雜湊碼,
比較:
HashMap的存入順序和輸出順序無關。
LinkedHashMap 則保留了鍵值對的存入順序。
TreeMap則是對Map中的元素進行排序。
因為HashMap和LinkedHashMap 儲存資料的速度比直接使用TreeMap 要快,存取效率要高。
當完成了所有的元素的存放後,我們再對整個的Map中的元素進行排序。這樣可以提高整個程式的執行的效率,縮短執行時間。
注意:TreeMap中是根據鍵(Key)進行排序的。而如果我們要使用TreeMap來進行正常的排序的話,Key 中存放的物件必須實現Comparable 介面。

Set:
擴充套件Collection介面
不允許重複元素
對 add()、equals() 和 hashCode() 方法添加了限制
HashSet和TreeSet是Set的實現
Set—》hashSet linkedHashSet
SortedSet —》 TreeSet

HashSet常用方法:
public boolean contains(Object o) :如果set包含指定元素,返回true
public Iterator iterator()返回set中元素的迭代器
public Object[] toArray() :返回包含set中所有元素的陣列public Object[] toArray(Object[] a) :返回包含set中所有元素的陣列,返回陣列的執行時型別是指定陣列的執行時型別
public boolean add(Object o) :如果set中不存在指定元素,則向set加入
public boolean remove(Object o) :如果set中存在指定元素,則從set中刪除
public boolean removeAll(Collection c) :如果set包含指定集合,則從set中刪除指定集合的所有元素
public boolean containsAll(Collection c) :如果set包含指定集合的所有元素,返回true。如果指定集合也是一個set,只有是當前set的子集時,方法返回true

實現Set介面的HashSet,依靠HashMap來實現的。
我們應該為要存放到散列表的各個物件定義hashCode()和equals()。
如何達到不能存在重複元素的目的?
“鍵”就是我們要存入的物件,“值”則是一個常量。這樣可以確保,我們所需要的儲存的資訊
之是“鍵”。而“鍵”在Map中是不能重複的,這就保證了我們存入Set中的所有的元素都不重複。
HashSet如何過濾重複元素
呼叫元素HashCode獲得雜湊碼--》判斷雜湊碼是否相等,不相等則錄入
---》相等則判斷equals()後是否相等,不相等在進行 hashcode錄入,相等不錄入

TreeSet:
TreeSet是依靠TreeMap來實現的。
TreeSet是一個有序集合,TreeSet中元素將按照升序排列,預設是按照自然順序進行排列,意味著TreeSet中元素要實現Comparable介面
我們可以在構造TreeSet物件時,傳遞實現了Comparator介面的比較器物件。

幾種Set的比較:
HashSet外部無序地遍歷成員。
成員可為任意Object子類的物件,但如果覆蓋了equals方法,同
時注意修改hashCode方法。
TreeSet外部有序地遍歷成員;
附加實現了SortedSet, 支援子集等要求順序的操作
成員要求實現Comparable介面,或者使用Comparator構造
TreeSet。成員一般為同一型別。
LinkedHashSet外部按成員的插入順序遍歷成員
成員與HashSet成員類似
HashSet是基於Hash演算法實現的,其效能通常都優於TreeSet。我們通常都應該使用HashSet,在我們需要排序的功能時,我們才使用TreeSet。

HashSet的元素存放順序和我們新增進去時候的順序沒有任何關係,而LinkedHashSet 則保持元素的新增順序。TreeSet則是對我們的Set中的元素進行排序存放。

一般來說,當您要從集合中以有序的方式抽取元素時,TreeSet 實現就會有用處。為了能順利進行,新增到 TreeSet 的元素必須是可排序的。 而您同樣需要對新增到TreeSet中的類物件實現 Comparable 介面的支援。一般說來,先把元素新增到 HashSet,再把集合轉換為 TreeSet 來進行有序遍歷會更快。

Comparable和Comparator
Comparable 介面以提供自然排序順序。
對於那些沒有自然順序的類、或者當您想要一個不同於自然順序的順序時,您可以實現
Comparator 介面來定義您自己的排序函式。可以將Comparator傳遞給Collections.sort或Arrays.sort。

Comparator介面
當一個類並未實現Comparable,或者不喜歡預設的Comaparable行為。可以實現Comparator介面
直接實現Comparator的compare介面完成自定義比較類。
例:Arrays.sort(results, new Comparator<RepDataQueryResultVO>() 陣列排序 RepDataQueryExecutor
例:Collections.sort(lst,new Comparator<TaskPrintSchemeVO>()