亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Java溫故而知新(1)集合類

2019-11-14 15:13:23
字體:
來源:轉載
供稿:網友

java中的集合類有以下所屬關系:
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap

java_Collection_介紹

Collection接

  Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些 Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。
  所有實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用于創建一個空的Collection,有一個 Collection參數的構造函數用于創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。后 一個構造函數允許用戶復制一個Collection。
  如何遍歷Collection中的每一個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:

Iterator it = collection.iterator(); // 獲得一個迭代子    while(it.hasNext()) {      Object obj = it.next(); // 得到下一個元素    }

  由Collection接口派生的兩個接口是List和Set。

 

java_Collection_介紹

 

所謂框架就是一個類庫的集合。集合框架就是一個用來表示和操作集合的統一的架構, 包含了實現集合的接口與類。

 

 

 

List接口
  List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數組下標)來訪問List中的元素,這類似于Java的數組。
和下面要提到的Set不同,List允許有相同的元素。
  除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個 ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素, 還能向前或向后遍歷。
  實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。

LinkedList類
  LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在 LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。
  注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。

一種解決方法是在創建List時構造一個同步的List:
    List list = Collections.synchronizedList(new LinkedList(...));

ArrayList類
  ArrayList實現了可變大小的數組。它允許所有元素,包括null。ArrayList沒有同步。
size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間為線性。
  每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法 并沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。
  和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。

Vector類
  Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和 ArrayList創建的Iterator是同一接口,但是,因為Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了 Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出 ConcurrentModificationException,因此必須捕獲該異常。

Stack 類
  Stack繼承自Vector,實現一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用?;镜膒ush和pop 方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創建后是空棧。

Set接口
  Set是一種不包含重復的元素且無序的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。
  很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重復的元素。
  請注意:必須小心操作可變對象(Mutable Object)。如果一個Set中的可變元素改變了自身狀態導致Object.equals(Object)=true將導致一些問題。

Map接口
  請注意,Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個 value。Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。

Hashtable類
  Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。
  添加數據使用put(key, value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。
Hashtable通過initial capacity和load factor兩個參數調整性能。通常缺省的load factor 0.75較好地實現了時間和空間的均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。
使用Hashtable的簡單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:
    Hashtable numbers = new Hashtable();
    numbers.put(“one”, new Integer(1));
    numbers.put(“two”, new Integer(2));
    numbers.put(“three”, new Integer(3));
  要取出一個數,比如2,用相應的key:
    Integer n = (Integer)numbers.get(“two”);
    System.out.PRintln(“two = ” + n);
  由于作為key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作為key的對象都必須實現hashCode和equals方 法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相 同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如 果兩個不同對象的hashCode相同,這種現象稱為沖突,沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希 表的操作。
  如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時復寫equals方法和hashCode方法,而不要只寫其中一個。
  Hashtable是同步的。

HashMap類
  HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null value和null key。,但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap 的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。

 HashMap的數據結構:
   在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。

   從上圖中可以看出,HashMap底層就是一個數組結構,數組中的每一項又是一個鏈表。當新建一個HashMap的時候,就會初始化一個數組。
 
下面以HashMap為例子,深入對Map的實現機制進行了解,在這個過程中,請打開jdk源碼。

Hash算法

HashMap使用Hash算法,所以在解剖HashMap之間,需要先簡單的了解Hash算法,Hash算法一般也成為散列算法,通過散列算法將任意的值轉化成固定的長度輸出,該輸出就是散列值,這是一種壓縮映射,也就是,散列值的空間遠遠小于輸入的值空間。
簡單的說,hash算法的意義在于提供了一種快速存取數據的方法,它用一種算法建立鍵值與真實值之間的對應關系,(每一個真實值只能有一個鍵值,但是一個鍵值可以對應多個真實值),這樣可以快速在數組等里面存取數據。

下面我們建立一個HashMap,然后往里面放入12對key-value,這個HashMap的默認數組長度為16,我們的key分別存放在該數組的格子中,每個格子下面存放的元素又是以鏈表的方式存放元素。

    public static void main(String[] args) {        Map map = new HashMap();        map.put("What", "chenyz");        map.put("You", "chenyz");        map.put("Don't", "chenyz");        map.put("Know", "chenyz");        map.put("About", "chenyz");        map.put("Geo", "chenyz");        map.put("APIs", "chenyz");        map.put("Can't", "chenyz");        map.put("Hurt", "chenyz");        map.put("you", "chenyz");        map.put("google", "chenyz");        map.put("map", "chenyz");        map.put("hello", "chenyz");    }

 


當我們新添加一個元素時,首先我們通過Hash算法計算出這個元素的Hash值的hashcode,通過這個hashcode的值,我們就可以計算出這個新元素應該存放在這個hash表的哪個格子里面,如果這個格子中已經存在元素,那么就把新的元素加入到已經存在格子元素的鏈表中。

運行上面的程序,我們對HashMap源碼進行一點修改,打印出每個key對象的hash值

What-->hash值:8
You-->hash值:3
Don't-->hash值:7
Know-->hash值:13
About-->hash值:11
Geo-->hash值:12
APIs-->hash值:1
Can't-->hash值:7
Hurt-->hash值:1
you-->hash值:10
google-->hash值:3
map-->hash值:8
hello-->hash值:0

計算出來的Hash值分別代表該key應該存放在Hash表中對應數字的格子中,如果該格子已經有元素存在,那么該key就以鏈表的方式依次放入格子中



從上表可以看出,Hash表是線性表和鏈表的綜合所得,根據數據結構的定義,可以得出粗劣的結論,Hash算法的存取速度要比數組差一些,但是比起單純的鏈表,在查找和存取方面卻要好多。

如果要查找一個元素時,同樣的方式,通過Hash函數計算出這個元素的Hash值hashcode,然后通過這個hashcode值,直接找到跟這個hash值相對應的線性格子,進如該格子后,對這個格子存放的鏈表元素逐個進行比較,直到找到對應的hash值。

在簡單了解完Hash算法后,我們打開HashMap源碼

初始化HashMap

下面我們看看Map map = new HashMap();這段代碼究竟做了什么,發生了什么數據結構的變化。

HashMap中幾個重要的屬性

transient Entry[] table;
用來保存key-value的對象Entry數組,也就是Hash表

transient int size;
返回HashMap的鍵值對個數

final float loadFactor;
負載因子,用來決定Entry數組是否擴容的因子,HashMap默認是0.75f

int threshold;
重構因子,(capacity * load factor)負載因子與Entry[]數組容積的乘值

public class HashMap<K,V>    extends AbstractMap<K,V>    implements Map<K,V>, Cloneable, Serializable{    int threshold;        final float loadFactor;    transient Entry[] table;    static final float DEFAULT_LOAD_FACTOR = 0.75f;    static final int DEFAULT_INITIAL_CAPACITY = 16;    public HashMap(int initialCapacity, float loadFactor) {        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal initial capacity: " +                                               initialCapacity);        if (initialCapacity > MAXIMUM_CAPACITY)            initialCapacity = MAXIMUM_CAPACITY;        if (loadFactor <= 0 || Float.isNaN(loadFactor))            throw new IllegalArgumentException("Illegal load factor: " +                                               loadFactor);        // Find a power of 2 >= initialCapacity        int capacity = 1;        while (capacity < initialCapacity)            capacity <<= 1;        this.loadFactor = loadFactor;        threshold = (int)(capacity * loadFactor);        table = new Entry[capacity];        init();    }

 

以public HashMap(int initialCapacity, float loadFactor)構造函數為例,另外兩個構造函數實際上也是以同種方式來構建HashMap.

首先是要確定hashMap的初始化的長度,這里使用的策略是循環查出一個大于initialCapacity的2的次方的數,例如initialCapacity的值是10,那么大于10的數是2的4次方,也就是16,capacity的值被賦予了16,那么實際上table數組的長度是16,之所以采用這樣的策略來構建Hash表的長度,是因為2的次方運算對于計算機來說是有相當的效率。

loadFactor,被稱為負載因子,HashMap的默認負載因子是0.75f

threshold,接下來是重構因子,由負載因子和容量的乘機組成,它表示當HashMap元素被存放了多少個之后,需要對HashMap進行重構。

通過這一系列的計算和定義后,初始化Entry[] table;

put(key,value)

接下來看一對key-value是如何被存放到HashMap中:put(key,value)

 
   public V put(K key, V value) {        if (key == null)            return putForNullKey(value);        int hash = hash(key.hashCode());                int i = indexFor(hash, table.length);        System.out.println(key+"-->hash值:"+i);//這就是剛才程序打印出來的key對應hash值        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {                V oldValue = e.value;                e.value = value;                e.recordaccess(this);                return oldValue;            }        }        modCount++;        addEntry(hash, key, value, i);        return null;    }    static int hash(int h) {        h ^= (h >>> 20) ^ (h >>> 12);        return h ^ (h >>> 7) ^ (h >>> 4);    }    static int indexFor(int h, int length) {        return h & (length-1);    }

 


這里是整個hash的關鍵,請打開源碼查看一步一步查看。

hash(key.hashCode()) 計算出key的hash碼 //對于hash()的算法,這里有一篇分析很透徹的文章<HashMap hash方法分析>
indexFor(hash, table.length) 通過一個與算法計算出來,該key應在存放在Hash表的哪個格子中。
for (Entry<K,V> e = table[i]; e != null; e = e.next) 然后再遍歷table[i]格中的鏈表,判斷是否已經存在一樣的key,如果存在一樣的key值,那么就用新的value覆蓋舊的value,并把舊的value值返回。
addEntry(hash, key, value, i) 如果經過遍歷鏈表沒有發現同樣的key,那么進行addEntry函數的操作,增加當前key到hash表中的第i個格子中的鏈表中

    void addEntry(int hash, K key, V value, int bucketIndex) {        Entry<K,V> e = table[bucketIndex];        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);        if (size++ >= threshold)            resize(2 * table.length);    }

 


Entry<K,V> e = table[bucketIndex];
  創建一個Entry對象來存放鍵值(ps:Entry對象是一個鏈表對象)
table[bucketIndex] = new Entry<K,V>(hash, key, value, e); 將Entry對象添加到鏈表中
if (size++ >= threshold) resize(2 * table.length); 最后將size進行自增,判斷size值是否大于重構因子,如果大于那么就是用resize進行擴容重構。

    void resize(int newCapacity) {        Entry[] oldTable = table;        int oldCapacity = oldTable.length;        if (oldCapacity == MAXIMUM_CAPACITY) {            threshold = Integer.MAX_VALUE;            return;        }        Entry[] newTable = new Entry[newCapacity];        transfer(newTable);        table = newTable;        threshold = (int)(newCapacity * loadFactor);    }

 


這里為什么是否需要擴容重構,其實是涉及到負載因子的性能問題

loadFactor負載因子
上面說過loadFactor是一個hashMap的決定性屬性,HashSet和HashMap的默認負載因子都是0.75,它表示,如果哈希表的容量超過3/4時,將自動成倍的增加哈希表的容量,這個值是權衡了時間和空間的成本,如果負載因子較高,雖然會減少對內存空間的需求,但也會增加查找數據的時間開銷,無論是put()和get()都涉及到對數據進行查找的動作,所以負載因子是不適宜設置過高



get(key)

接下來看看get(key)做了什么

    public V get(Object key) {        if (key == null)            return getForNullKey();        int hash = hash(key.hashCode());        for (Entry<K,V> e = table[indexFor(hash, table.length)];             e != null;             e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))                return e.value;        }        return null;    }

 


這些動作似乎是跟put(key,value)相識,通過hash算法獲取key的hash碼,再通過indexFor定位出該key存在于table的哪一個下表,獲取該下標然后對下標中的鏈表進行遍歷比對,如果有符合就直接返回該key的value值。

keySet()

這里還涉及另一個問題,上面說了HashMap是跟set沒有任何親屬關系,但map也一樣實現了keySet接口,下面譜析一下keySet在hashMap中是如何實現的,這里給出部分代碼,請結合源碼查看

public K next() {            return nextEntry().getKey();        }    final Entry<K,V> nextEntry() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();            Entry<K,V> e = next;            if (e == null)                throw new NoSuchElementException();            if ((next = e.next) == null) {                Entry[] t = table;                while (index < t.length && (next = t[index++]) == null)                    ;            }        current = e;            return e;        }

 


代碼很簡單,就是對每個格子里面的鏈表進行遍歷,也正是這個原因,當我們依次將key值put進hashMap中,但在使用map.entrySet().iterator()進行遍歷時候卻不是put時候的順序。

擴容
在前面說到put函數的時候,已經提過了擴容的問題

if (size++ >= threshold)
resize(2 * table.length);


這里一個是否擴容的判斷,當數據達到了threshold所謂的重構因子,而不是HashMap的最大容量,就進行擴容。

    
void resize(int newCapacity) {        Entry[] oldTable = table;        int oldCapacity = oldTable.length;        if (oldCapacity == MAXIMUM_CAPACITY) {            threshold = Integer.MAX_VALUE;            return;        }        Entry[] newTable = new Entry[newCapacity];        transfer(newTable);        table = newTable;        threshold = (int)(newCapacity * loadFactor);    }    void transfer(Entry[] newTable) {        Entry[] src = table;        int newCapacity = newTable.length;        for (int j = 0; j < src.length; j++) {            Entry<K,V> e = src[j];            if (e != null) {                src[j] = null;                do {                    Entry<K,V> next = e.next;                    int i = indexFor(e.hash, newCapacity);                    e.next = newTable[i];                    newTable[i] = e;                    e = next;                } while (e != null);            }        }    }
transfer方法實際上是將所有的元素重新進行一些hash,這是因為容量變化了,每個元素相對應的hash值也會不一樣。

使用HashMap

1.不要再高并發中使用HashMap,HashMap是線程不安全,如果被多個線程共享之后,將可能發生不可預知的問題。
2.如果數據大小事固定的,最好在初始化的時候就給HashMap一個合理的容量值,如果使用new HashMap()默認構造函數,重構因子的值是16*0.75=12,當HashMap的容量超過了12后,就會進行一系列的擴容運算,重建一個原來成倍的數組,并且對原來存在的元素進行重新的hash運算,如果你的數據是有成千上萬的,那么你的成千上萬的數據也要跟這你的擴容不斷的hash,這將產生高額的內存和cpu的大量開銷。

當然啦,HashMap的函數還有很多,不過都是基于table的鏈表進行操作,當然也就是hash算法,Map & hashMap在平時我們的應用非常多,最重要的是我們要對每句代碼中每塊數據結構變化心中有數。

WeakHashMap類
  WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被GC回收。

總結
  如果涉及到堆棧,隊列等操作,應該考慮用List,對于需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。
  如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。
  要特別注意對哈希表的操作,作為key的對象要正確復寫equals和hashCode方法。
  盡量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。

同步性
Vector是同步的。這個類中的一些方法保證了Vector中的對象是線程安全的。而ArrayList則是異步的,因此ArrayList中的對象并 不是線程安全的。因為同步的要求會影響執行的效率,所以如果你不需要線程安全的集合那么使用ArrayList是一個很好的選擇,這樣可以避免由于同步帶 來的不必要的性能開銷。
數據增長
從內部實現機制來講ArrayList和Vector都是使用數組(Array)來控制集合中的對象。當你向這兩種類型中增加元素的時候,如果元素的數目 超出了內部數組目前的長度它們都需要擴展內部數組的長度,Vector缺省情況下自動增長原來一倍的數組長度,ArrayList是原來的50%,所以最 后你獲得的這個集合所占的空間總是比你實際需要的要大。所以如果你要在集合中保存大量的數據那么使用Vector有一些優勢,因為你可以通過設置集合的初 始化大小來避免不必要的資源開銷。
使用模式
在ArrayList和Vector中,從一個指定的位置(通過索引)查找數據或是在集合的末尾增加、移除一個元素所花費的時間是一樣的,這個時間我們用 O(1)表示。但是,如果在集合的其他位置增加或移除元素那么花費的時間會呈線形增長:O(n-i),其中n代表集合中元素的個數,i代表元素增加或移除 元素的索引位置。為什么會這樣呢?以為在進行上述操作的時候集合中第i和第i個元素之后的所有元素都要執行位移的操作。這一切意味著什么呢?
這意味著,你只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是其他操作,你最好選擇其他 的集合操作類。比如,LinkList集合類在增加或移除集合中任何位置的元素所花費的時間都是一樣的?O(1),但它在索引一個元素的使用缺比較慢 -O(i),其中i是索引的位置.使用ArrayList也很容易,因為你可以簡單的使用索引來代替創建iterator對象的操作。LinkList也 會為每個插入的元素創建對象,所有你要明白它也會帶來額外的開銷。
最后,在《Practical Java》一書中Peter Haggar建議使用一個簡單的數組(Array)來代替Vector或ArrayList。尤其是對于執行效率要求高的程序更應如此。因為使用數組 (Array)避免了同步、額外的方法調用和不必要的重新分配空間的操作。

相互區別

Vector和ArrayList

1,vector是線程同步的,所以它也是線程安全的,而arraylist是線程異步的,是不安全的。如果不考慮到線程的安全因素,一般用

arraylist效率比較高。
2,如果集合中的元素的數目大于目前集合數組的長度時,vector增長率為目前數組長度的100%,而arraylist增長率為目前數組長度

的50%.如過在集合中使用數據量比較大的數據,用vector有一定的優勢。
3,如果查找一個指定位置的數據,vector和arraylist使用的時間是相同的,都是0(1),這個時候使用vector和arraylist都可以。而

如果移動一個指定位置的數據花費的時間為0(n-i)n為總長度,這個時候就應該考慮到使用linklist,因為它移動一個指定位置的數據

所花費的時間為0(1),而查詢一個指定位置的數據時花費的時間為0(i)。

ArrayList 和Vector是采用數組方式存儲數據,此數組元素數大于實際存儲的數據以便增加和插入元素,都允許直接序號索引元素,但是插入數據要設計到數組元素移動 等內存操作,所以索引數據快插入數據慢,Vector由于使用了synchronized方法(線程安全)所以性能上比ArrayList要 差,LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向后遍歷,但是插入數據時只需要記錄本項的前后項即可,所以插入數度較快!

arraylist和linkedlist

1.ArrayList是實現了基于動態數組的數據結構,LinkedList基于鏈表的數據結構。
2.對于隨機訪問get和set,ArrayList覺得優于LinkedList,因為LinkedList要移動指針。
3.對于新增和刪除操作add和remove,LinedList比較占優勢,因為ArrayList要移動數據。
    這一點要看實際情況的。若只對單條數據插入或刪除,ArrayList的速度反而優于LinkedList。但若是批量隨機的插入刪除數 據,LinkedList的速度大大優于ArrayList. 因為ArrayList每插入一條數據,要移動插入點及之后的所有數據。


HashMap與TreeMap


       1、HashMap通過hashcode對其內容進行快速查找,而TreeMap中所有的元素都保持著某種固定的順序,如果你需要得到一個有序的結果你就應該使用TreeMap(HashMap中元素的排列順序是不固定的)。

       2、在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那么TreeMap會更好。使用HashMap要求添加的鍵類明確定義了hashCode()和 equals()的實現?! ∵@個TreeMap沒有調優選項,因為該樹總處于平衡狀態。

      結過研究,在原作者的基礎上我還發現了一點,二樹map一樣,但順序不一樣,導致hashCode()不一樣。
      同樣做測試:
      在hashMap中,同樣的值的map,順序不同,equals時,false;
      而在treeMap中,同樣的值的map,順序不同,equals時,true,說明,treeMap在equals()時是整理了順序了的。

hashtable與hashmap

一.歷史原因:Hashtable是基于陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現

二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的

三.值:只有HashMap可以讓你將空值作為一個表的條目的key或value

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品日韩在线观看| 粉嫩av一区二区三区免费野| 日韩久久免费视频| 精品国产欧美一区二区五十路| 97精品视频在线播放| 国产精品成人久久久久| 国产精品美女在线观看| 亚洲国产私拍精品国模在线观看| 日韩中文字幕在线精品| 黑人巨大精品欧美一区二区一视频| 欧美人成在线视频| 成年人精品视频| 综合激情国产一区| 欧美电影在线观看完整版| 欧美有码在线观看视频| 色婷婷综合久久久久| 国产亚洲成av人片在线观看桃| 国产成人亚洲精品| 国产亚洲精品久久久| 91老司机精品视频| 日韩在线免费视频| 国产中文字幕日韩| 亚洲精品国产电影| 亚洲尤物视频网| 日韩女在线观看| 欧美大片免费看| 欧美中在线观看| 亚洲精品91美女久久久久久久| 2018日韩中文字幕| 亚洲欧美中文日韩在线| 久久久久久国产精品久久| 亚洲国产精品一区二区久| 国产女人精品视频| 国产中文日韩欧美| 97色在线观看免费视频| 韩国国内大量揄拍精品视频| 国产精品国内视频| 色综合久久久久久中文网| 亚洲欧美成人网| 亚洲视频在线观看免费| 国产成人综合av| 欧美第一淫aaasss性| 91高清免费视频| 中文字幕欧美日韩在线| 91精品国产免费久久久久久| 亚洲欧美日韩高清| 国产乱肥老妇国产一区二| 久久久久久久久久国产| 欧美小视频在线观看| 精品欧美一区二区三区| 亚洲欧美日韩国产中文专区| 欧美日韩国产精品一区二区不卡中文| 欧美国产高跟鞋裸体秀xxxhd| 亚洲第一视频在线观看| 97视频在线观看视频免费视频| 亚洲肉体裸体xxxx137| 国产精品亚发布| 国产精品视频一区国模私拍| 亚洲国产97在线精品一区| 国产精品国产三级国产专播精品人| 日韩hd视频在线观看| 日韩精品免费观看| 亚洲精品美女在线观看| 久久91亚洲精品中文字幕奶水| 成人h片在线播放免费网站| 国产精品爱啪在线线免费观看| 精品久久久视频| 日韩高清中文字幕| 欧美极度另类性三渗透| 日韩高清电影免费观看完整版| 久久99亚洲精品| 青青草成人在线| 亚洲人午夜色婷婷| 午夜精品一区二区三区av| 亚洲欧美精品伊人久久| 57pao国产成人免费| 91久久精品久久国产性色也91| 国产在线拍偷自揄拍精品| 日韩精品在线观看一区二区| 亚洲精品国产综合久久| 亚洲成人国产精品| 国模叶桐国产精品一区| 成人在线激情视频| 国产欧美一区二区三区四区| 精品一区二区三区电影| 日本韩国欧美精品大片卡二| 色综合天天狠天天透天天伊人| 亚洲欧美中文日韩在线v日本| 日韩在线视频国产| 97精品久久久| 久久视频精品在线| 欧美激情一区二区三级高清视频| 欧美色欧美亚洲高清在线视频| 国产精品久久婷婷六月丁香| 日韩网站免费观看| 伊人一区二区三区久久精品| 国精产品一区一区三区有限在线| 98精品在线视频| 日本韩国欧美精品大片卡二| 欧美激情精品久久久久久| 国产香蕉精品视频一区二区三区| 成人免费网站在线观看| 国产免费成人av| 久久精品国产久精国产思思| 日韩精品在线私人| 亚洲一区制服诱惑| 欧美视频不卡中文| 超碰精品一区二区三区乱码| 26uuu另类亚洲欧美日本一| 这里只有精品在线观看| 日韩国产在线播放| 欧美日韩国产精品一区| 精品国产欧美一区二区三区成人| 国产精品av网站| 日韩在线免费视频观看| 久久激情视频久久| 亚洲欧美国产精品| 亚洲国产中文字幕久久网| 亚洲欧美日韩国产成人| 国产精品电影久久久久电影网| 日韩av电影在线免费播放| 欧美日韩亚洲国产一区| 欧美一级电影免费在线观看| 亚洲国产精品999| 国产精品国产自产拍高清av水多| 欧美贵妇videos办公室| 亚洲国产成人久久综合| 欧美性猛交xxxx偷拍洗澡| 亚洲天堂色网站| 亚洲国产毛片完整版| 国产亚洲欧美一区| 国外日韩电影在线观看| 国产精品偷伦免费视频观看的| 亚洲国产中文字幕在线观看| 欧美国产日本在线| 久久精品视频播放| 亚洲a级在线播放观看| 欧美黑人xxxⅹ高潮交| 色综合久综合久久综合久鬼88| 96pao国产成视频永久免费| 91高潮在线观看| 亚洲精品视频二区| 91欧美精品午夜性色福利在线| 欧美在线视频在线播放完整版免费观看| 国产激情综合五月久久| 在线观看不卡av| 国产一区二区三区直播精品电影| 日韩成人久久久| 日本精品视频网站| 精品久久久久久久久久久久久| 中文国产成人精品| 色偷偷av一区二区三区| 亚洲自拍在线观看| 国产欧美在线播放| 91高清视频免费| 久久精品夜夜夜夜夜久久| 国产精品亚洲第一区| 日韩av在线一区二区| 精品国产成人在线| 欧美色视频日本高清在线观看| 亚洲国产日韩欧美在线动漫| 亚洲第一精品夜夜躁人人躁| 欧美在线一级va免费观看| 欧美视频精品一区|