(一) Vector ArrayList LinkedListjava
Vestor,ArrayList,LinkedList這三個類都實現了java.util.List接口;數組
Vector和ArrayList使用Objec的數組形式來存儲,可直接按序號索引元素,故搜索速度較快,但在數組中間插入新元素時要設計數組元素的內存移動,致使速度較慢;安全
LinkedList則是採用了雙向鏈表的存儲方式,插入新元素時只要指定該元素的先後項便可,速度較快,可是搜索時要向前或向後遍歷,速度較慢函數
Vector是線程安全的,他的不少方法都實現了線程同步(synchronized),可是性能上來說,Vector會低於ArrayList性能
(二)HashSetthis
HashSet 是 Set 接口的經常使用實現類,構造函數以下:spa
public HashSet() {
map = new HashMap<E,Object>();
}線程
從構造函數咱們能夠看出,實際上HashSet是經過HashMap來實現的,所以HashSet也是採用Hash存儲機制進行數據的存儲。設計
咱們都知道HashSet不容許插入重複的值或對象,可是對於兩個內容相同的對象呢?code
運行下面的代碼我便能知曉一二:
public class Test { //定義一個內部類 private static class Demo{ private int value; public Demo(int value){ this.value=value; } //重寫toString方法,便於打印輸出 public String toString(){ return ("value="+value); } //重寫equals方法 public boolean equals(Object o) { Demo demo = (Demo) o; return (demo.value == value) ? true : false; } //重寫hashCode方法 public int hashCode(){ return value; } } public static void main(String[] args) { HashSet<Demo> set=new HashSet<Demo>(); set.add(new Demo(1)); System.out.println(set); set.add(new Demo(1)); System.out.println(set); } }
運行結果爲:
[value=1]
[value=1]
可是當咱們把Demo的equals方法或hashCode方法註釋掉一個或者所有註釋掉時咱們會發現運行結果變爲:
[value=1]
[value=1, value=1]
若是不重寫對象的hashCode方法和equals方法的狀況下,HashSet依舊會將內容相同的兩個對象一塊兒存入
那麼爲何會如此呢?
因爲HashSet是依靠HashMap實現的,因此要解答這個問題咱們必須搞清楚HashMap內部的存儲機制
經過另外一篇文章——深刻講解HashMap,咱們能夠發現,鍵值對在存入HashMap中定義的entry數組時,會先根據鍵(key)對象的hashCode計算出要存儲在數組的那個下標值下,而後在遍歷該下標值的entry鏈,若是找到了key與要插入的key相同的entry對象則替換該對象的值,不然,則將此新鍵值對插入到該entry鏈的頭部;
而對於HashSet<E>事實上就至關於HashMap<E,Object>
若是不重寫hashCode方法,那麼咱們知道Object默認的hashCode返回的是一個與內存地址相關的數值,兩個不一樣對象的hashCode返回值通常是不相同的(固然也有很小的概率相同),哪怕是這兩個對象的內容徹底一致,因此在插入entry數組的時候,這兩個對象存儲的下標值也有很大的機率不在同一個下標值內,天然就兩個對象都會被存儲在entry數組中;
那麼即便咱們重寫了hashCode也仍是不夠,由於在entry鏈中,會根據對象的equals方法判斷新添加進來的key時候已經存在,咱們知道Object默認的equals方法返回的是該對象的內存地址,天然的,兩個不一樣對象用equals進行比較時返回的就是false,也就是此時這兩個對象都會被存儲再同一個entry鏈中。
明白了上面的機制後,咱們能夠看出,若是咱們要實如今HashSet(或者是HashMap的key)中不會被插入內容相同的對象時,咱們就必須重寫要插入的對象的hashCode和equals方法,並且這兩個方法要根據該對象的內容來重寫,確保兩個內容相同的對象的hashCode返回值相同,並使用equals比較時返回true
(三)TreeSet TreeMap HashSet HashMap
TreeMap它內部是一個樹形結構存儲結構,使用二叉樹對數據進行存儲;
TreeMap是有序的,天然要求元素是能夠比較大小的,若是構造函數指定Comparator的話,就使用這個Comparator比較大小
若是沒有指定Comparator的話,就使用天然排序(元素要實現Comparable接口).
二叉樹,通常查找時間複雜度爲 o(lg(n)),這個效率固然沒有HashMap的效率高因此除法是有排序的需求,否則通常都使用HashMap
TreeSet與TreeMap的關係就和HashSet與HashMap的關係同樣
因爲TreeSet TreeMap 用的比較少,因此也未做深刻的瞭解,具體之後有須要再進一步分析
(四)HashMap Hashtalbe
Hashtable是繼承與Dictionary類,HashMap是Map接口的一個實現(事實上,Hashtable也實現了Map接口);
Hashtable是線程安全,HashMap是Hashtable的輕量級實現(非線程安全實現),因此HashMap的效率會高於Hashtable
HashMap容許將null做爲一個entry的key或者value,而Hashtable不容許。
(五)關於集合的遍歷
package com; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; public class 容器類的遍歷 { //有序的集合:數組和arraylist的遍歷,可經過下標值實現 public void bianliArray(String[] a){ for(int i=0;i<a.length;i++){ System.out.println(i); } } public void bianliArraylist(ArrayList<String> a){ for(int i=0;i<a.size();i++){ System.out.println(a.get(i)); } } //Collection接口定義了一個iterator()方法,該方法返回一個實現了Iterator接口對象(迭代器),而後再使用迭代器進行迭代遍歷 public void bianliCollection(Collection<String> c){ Iterator<String> iterator=c.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); /* * 補充: 值得注意的是,當要在迭代過程當中刪除某個元素,則必需要用該迭代器的remove方法 * 而不能使用collection自生的remove方法,這是由於集合進行進入迭代器時會被迭代器鎖定, * 迭代過程只有迭代器能對此集合進行操做 */ } } //java5以後支持了另外一種 遍歷方式:foreach方式,這種方式的編寫格式簡單整潔,可是隻能用於只讀的狀況, //由於該方法不能對遍歷的元素進行修改和刪除操做,分析下面的方法的結果能夠發現集合中的字符串沒被修改過 public void bianliForeach(Collection<String> c){ for(String s: c){ System.out.println(s); s="被修改過了"; } for(String s: c){ System.out.println(s); } } //可是分析下面這個程序能夠發現集合中的u對象倒是被修改了,從中能夠看出什麼麼?。。。。 public void bianliForeach1(Collection<User> c){ for(User u: c){ System.out.println(u.getName()); u.setName("被修改過了"); } for(User u: c){ System.out.println(u.getName()); } } /* * 對於map的遍歷,因爲Map接口沒有定義和collection同樣的iterator方法 * 不過在Map中定義裏entrySet和ketSet方法 * entrySet()返回此映射中包含的映射關係的 Set視圖, * keySet() 返回此映射中包含的鍵的 Set 視圖。 * 而後在經過set視圖的iterator方法 */ //用entrySet實現Map的遍歷,效率較高 public void entrySetOfMap(Map<String, String> m){ Iterator iterator=m.entrySet().iterator(); while(iterator.hasNext()){ Map.Entry<String, String> entry=(Map.Entry<String, String>)iterator.next();//Map.Entry鍵值對映射項 System.out.println("key="+entry.getKey()); System.out.println("value="+entry.getValue()); } } //用keySet實現Map的遍歷,遍歷出key以後還要去map查找對應的value,效率較低 public void keySetOfMap(Map<String, String> m){ Iterator iterator=m.keySet().iterator(); while(iterator.hasNext()){ Object key=iterator.next(); String value=(String)m.get(key); System.out.println("key="+key); System.out.println("value="+value); } } }