java中有幾種常用的數據結構,主要分為Collection和map兩個主要接口(接口只提供方法,並不提供實現),而程序中最終使用的數據結構是繼承自這些接口的數據結構類。
一、集合和數組的區別
二、Collection集合和Map集合
三、Collection接口
1、定義
public interface Collection<E> extends Iterable<E> {}
它是一個接口,是高度抽象出來的集合,它包含了集合的基本操作:添加、刪除、清空、遍歷(讀取)、是否為空、獲取大小、是否保護某元素等等。
Collection接口的所有子類(直接子類和間接子類)都必須實現2種構造函數:不帶參數的構造函數 和 參數為Collection的構造函數。帶參數的構造函數,可以用來轉換Collection的類型。
2、Collection集合的API
四、List
1、定義:
List是一個繼承於Collection的接口,即List是集合中的一種。List是有序的隊列,List中的每一個元素都有一個索引;第一個元素的索引值是0,往后的元素的索引值依次+1。和Set不同,List中允許有重復的元素。
public interface List<E> extends Collection<E> {}
2、List接口的實現類
(1)ArrayList:底層數據結構是數組,查詢快,增刪慢,線程不安全,效率高,可以存儲重復元素
(2)LinkedList 底層數據結構是鏈表,查詢慢,增刪快,線程不安全,效率高,可以存儲重復元素
(3)Vector:底層數據結構是數組,查詢快,增刪慢,線程安全,效率低,可以存儲重復元素
3、List接口的方法:既然List是繼承於Collection接口,它自然就包含了Collection中的全部函數接口;由於List是有序隊列,它也額外的有自己的API接口。
Arraylist:
優點:ArrayList是實現了基於動態數組的數據結構,因為地址連續,一旦數據存儲好了,查詢操作效率會比較高(在內存里是連着放的)。
缺點:因為地址連續, ArrayList要移動數據,所以插入和刪除操作效率比較低。
LinkedList:
優點:LinkedList基於鏈表的數據結構,地址是任意的,所以在開辟內存空間的時候不需要等一個連續的地址,對於新增和刪除操作add和remove,LinedList比較占優勢。LinkedList 適用於要頭尾操作或插入指定位置的場景
缺點:因為LinkedList要移動指針,所以查詢操作性能比較低。
適用場景分析:
當需要對數據進行對此訪問的情況下選用ArrayList,當需要對數據進行多次增加刪除修改時采用LinkedList。
五、Set集合
1、定義:Set是一個繼承於Collection的接口,即Set也是集合中的一種。Set是沒有重復元素的集合。
public interface Set<E> extends Collection<E> {}
2、Set的API和Collection完全一樣。
// Set的API abstract boolean add(E object) abstract boolean addAll(Collection<? extends E> collection) abstract void clear() abstract boolean contains(Object object) abstract boolean containsAll(Collection<?> collection) abstract boolean equals(Object object) abstract int hashCode() abstract boolean isEmpty() abstract Iterator<E> iterator() abstract boolean remove(Object object) abstract boolean removeAll(Collection<?> collection) abstract boolean retainAll(Collection<?> collection) abstract int size() abstract <T> T[] toArray(T[] array) abstract Object[] toArray()
3、實現子類
(1)HashSet : 底層數據結構采用哈希表實現,元素無序且唯一,線程不安全,效率高,可以存儲null元素,元素的唯一性是靠所存儲元素類型是否重寫hashCode()和equals()方法來保證的,如果沒有重寫這兩個方法,則無法保證元素的唯一性。
a、實現唯一性:
存儲元素首先會使用hash()算法函數生成一個int類型hashCode散列值,然后已經的所存儲的元素的hashCode值比較,如果hashCode不相等,則所存儲的兩個對象一定不相等,此時存儲當前的新的hashCode值處的元素對象;如果hashCode相等,存儲元素的對象還是不一定相等,此時會調用equals()方法判斷兩個對象的內容是否相等,如果內容相等,那么就是同一個對象,無需存儲;如果比較的內容不相等,那么就是不同的對象,就該存儲了,此時就要采用哈希的解決地址沖突算法,在當前hashCode值處類似一個新的鏈表, 在同一個hashCode值的后面存儲存儲不同的對象,這樣就保證了元素的唯一性。
b、實現不重復
HashSet也一樣他是使用了一種標識來確定元素的不重復,HashSet用一種算法來保證HashSet中的元素是不重復的, HashSet采用哈希算法,底層用數組存儲數據。默認初始化容量16,加載因子0.75。
Object類中的hashCode()的方法是所有子類都會繼承這個方法,這個方法會用Hash算法算出一個Hash(哈希)碼值返回,HashSet會用Hash碼值去和數組長度取模, 模(這個模就是對象要存放在數組中的位置)相同時才會判斷數組中的元素和要加入的對象的內容是否相同,如果不同才會添加進去。
覆蓋hashCode()方法的原則:
1、一定要讓那些我們認為相同的對象返回相同的hashCode值
2、盡量讓那些我們認為不同的對象返回不同的hashCode值,否則,就會增加沖突的概率。
3、盡量的讓hashCode值散列開(兩值用異或運算可使結果的范圍更廣)
c、HashSet的實現
HashSet 的實現比較簡單,相關HashSet的操作,基本上都是直接調用底層HashMap的相關方法來完成,我們應該為保存到HashSet中的對象覆蓋hashCode()和equals(),因為再將對象加入到HashSet中時:
首先調用hashCode方法計算出對象的hash值,接着根據此hash值調用HashMap中的hash方法,得到的值& (length-1)得到該對象在hashMap的transient Entry[] table中的保存位置的索引,接着找到數組中該索引位置保存的對象,並調用equals方法比較這兩個對象是否相等,如果相等則不添加;
注意:所以要存入HashSet的集合對象中的自定義類必須覆蓋hashCode(),equals()兩個方法,才能保證集合中元素不重復。在覆蓋equals()和hashCode()方法時, 要使相同對象的hashCode()方法返回相同值,覆蓋equals()方法再判斷其內容。為了保證效率,所以在覆蓋hashCode()方法時,也要盡量使不同對象盡量返回不同的Hash碼值。
(2)、LinkedHashSet底層數據結構采用鏈表和哈希表共同實現,鏈表保證了元素的順序與存儲順序一致,哈希表保證了元素的唯一性。線程不安全,效率高。
(3)、TreeSet底層數據結構采用二叉樹來實現,元素唯一且已經排好序;唯一性同樣需要重寫hashCode和equals()方法,二叉樹結構保證了元素的有序性。根據構造方法不同,分為自然排序(無參構造)和比較器排序(有參構造)。
自然排序要求元素必須實現Compareable接口,並重寫里面的compareTo()方法,元素通過比較返回的int值來判斷排序序列,返回0說明兩個對象相同,不需要存儲;
比較器排需要在TreeSet初始化是時候傳入一個實現Comparator接口的比較器對象,或者采用匿名內部類的方式new一個Comparator對象,重寫里面的compare()方法;
比較:
1、TreeSet 是二叉樹(紅黑樹的樹據結構)實現的,Treeset中的數據是自動排好序的,不允許放入null值;
2、HashSet 是哈希表實現的,HashSet中的數據是無序的,可以放入null,但只能放入一個null,兩者中的值都不能重復,就如數據庫中唯一約束 ;
3、HashSet要求放入的對象必須實現HashCode()方法,放入的對象,是以hashcode碼作為標識的,而具有相同內容的String對象,hashcode是一樣,所以放入的內容不能重復。但是同一個類的對象可以放入不同的實例;
適用場景分析:HashSet是基於Hash算法實現的,其性能通常都優於TreeSet。為快速查找而設計的Set,我們通常都應該使用HashSet,在我們需要排序的功能時,我們才使用TreeSet。
六、List和Set的比較
(1)、List,Set都是繼承自Collection接口;
(2)、List特點:元素有放入順序,元素可重復 ;Set特點:元素無放入順序,元素不可重復,重復元素會覆蓋掉;
(3)、Set:檢索元素效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變。
List:和數組類似,List可以動態增長,查找元素效率高,插入刪除元素效率低,因為會引起其他元素位置改變。
原文:https://blog.csdn.net/feiyanaffection/article/details/81394745
http://www.cnblogs.com/skywang12345/p/3308513.html