摘要:集合中成員很豐富,常用的集合有,,等。實現(xiàn)接口的集合主要有。集合中不能包含重復的元素,每個元素必須是唯一的。而以作為實現(xiàn)的構(gòu)造函數(shù)的訪問權(quán)限是默認訪問權(quán)限,即包內(nèi)訪問權(quán)限。與接口不同,它是由一系列鍵值對組成的集合,提供了到的映射。
原文地址
Java集合Java集合框架:是一種工具類,就像是一個容器可以存儲任意數(shù)量的具有共同屬性的對象。
Java集合中成員很豐富,常用的集合有ArrayList,HashMap,HashSet等。線程安全的有Vector,HashTable。線程不安全的有LinkedList,TreeMap,ArrayList,HashMap等等。
集合中用到的數(shù)據(jù)結(jié)構(gòu)有以下幾種:
數(shù)組:最常用的數(shù)據(jù)結(jié)構(gòu)之一。數(shù)組的特點是長度固定,可以用下標索引,并且所有的元素的類型都是一致的。使用時盡量把數(shù)組封裝在一個類里,防止數(shù)據(jù)被錯誤的操作弄亂。
鏈表:是一種由多個節(jié)點組成的數(shù)據(jù)結(jié)構(gòu),并且每個節(jié)點包含有數(shù)據(jù)以及指向下一個節(jié)點的引用,在雙向鏈表里,還會有一個指向前一個節(jié)點的引用。例如,可以用單向鏈表和雙向鏈表來實現(xiàn)堆棧和隊列,因為鏈表的兩端都是可以進行插入和刪除的動作的。當然,也會有在鏈表的中間頻繁插入和刪除節(jié)點的場景。
樹:是一種由節(jié)點組成的數(shù)據(jù)結(jié)構(gòu),每個節(jié)點都包含數(shù)據(jù)元素,并且有一個或多個子節(jié)點,每個子節(jié)點指向一個父節(jié)點可以表示層級關(guān)系或者數(shù)據(jù)元素的順序關(guān)系。如果樹的每個子節(jié)點最多有兩個葉子節(jié)點,那么這種樹被稱為二叉樹。二叉樹是一種非常常用的樹形結(jié)構(gòu), 因為它的這種結(jié)構(gòu)使得節(jié)點的插入和刪除都非常高效。樹的邊表示從一個節(jié)點到另外一個節(jié)點的快捷路徑。
堆棧:只允許對最后插入的元素進行操作(也就是后進先出,Last In First Out – LIFO)。如果你移除了棧頂?shù)脑兀敲茨憧梢圆僮鞯箶?shù)第二個元素,依次類推。這種后進先出的方式是通過僅有的peek(),push()和pop()這幾個方法的強制性限制達到的。這種結(jié)構(gòu)在很多場景下都非常實用,例如解析像(4+2)*3這樣的數(shù)學表達式,把源碼中的方法和異常按照他們出現(xiàn)的順序放到堆棧中,檢查你的代碼看看小括號和花括號是不是匹配的,等等。
隊列:和堆棧有些相似,不同之處在于在隊列里第一個插入的元素也是第一個被刪除的元素(即是先進先出)。這種先進先出的結(jié)構(gòu)是通過只提供peek(),offer()和poll()這幾個方法來訪問數(shù)據(jù)進行限制來達到的。例如,排隊等待公交車,銀行或者超市里的等待列隊等等,都是可以用隊列來表示。
Java集合框架圖
[圖片上傳失敗...(image-4b8b54-1530872801038)]
Collection interface如上圖所示,Collection接口是最基本的集合接口,它不提供直接的實現(xiàn),Java SDK提供的類都是繼承自Collection的“子接口”如List,Set和Queue。Collection所代表的是一種規(guī)則,它所包含的元素都必須遵循一條或者多條規(guī)則。如有些允許出現(xiàn)重復元素而有些則不允許重復、有些必須要按照順序插入而有些則是散列,有些支持排序但是有些則不支持等等。
ListList接口是Collection接口下的子接口。List所代表的是有序的Collection,即它用某種特定的插入順序來維護元素順序。用戶可以對列表中每個元素的插入位置進行精確地控制,同時可以根據(jù)元素的整數(shù)索引(在列表中的位置)訪問元素,并搜索列表中的元素。實現(xiàn)List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。
ArrayListArrayList基于數(shù)組實現(xiàn),可以通過下標索引直接查找到指定位置的元素,因此查找效率高,但每次插入或刪除元素,就要大量地移動元素,插入刪除元素的效率低。它允許任何符合規(guī)則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10),該容量代表了數(shù)組的大小。隨著容器中的元素不斷增加,容器的大小也會隨著增加。在每次向容器中增加元素的同時都會進行容量檢查,當快溢出時,就會進行擴容操作(擴容1.5倍)。所以如果我們明確所插入元素的多少,最好指定一個初始容量值,避免過多的進行擴容操作而浪費時間、效率。
ArrayList擅長于隨機訪問。同時ArrayList是非同步的,只能用在單線程環(huán)境下,多線程環(huán)境下可以考慮用Collections.synchronizedList(List l)函數(shù)返回一個線程安全的ArrayList類,也可以使用concurrent并發(fā)包下的CopyOnWriteArrayList類。
擴充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1個,也可能是一組)時,都要調(diào)用該方法來確保足夠的容量。當容量不足以容納當前的元素個數(shù)時,就設(shè)置新的容量為舊的容量的1.5倍,如果設(shè)置后的新容量還不夠,則直接新容量設(shè)置為傳入的參數(shù)(也就是所需的容量),而后用Arrays.copyof()方法將元素拷貝到新的數(shù)組。從中可以看出,當容量不夠時,每次增加元素,都要將原來的元素拷貝到一個新的數(shù)組中,非常之耗時,也因此建議在事先能確定元素數(shù)量的情況下,才使用ArrayList,否則建議使用LinkedList。
ArrayList的具體實現(xiàn)請參考這里
LinkedListLinkedList同樣實現(xiàn)List接口,與ArrayList不同的是,LinkedList是基于雙向鏈表實現(xiàn)的,可以在任何位置進行高效地插入和移除操作。但是LinkedList不能隨機訪問,它所有的操作都是要按照雙重鏈表的需要執(zhí)行。在列表中索引的操作將從開頭或結(jié)尾遍歷列表(從靠近指定索引的一端)。這樣做的好處就是可以通過較低的代價在List中進行插入和刪除操作。
與ArrayList一樣,LinkedList也是非同步的。如果多個線程同時訪問一個List,則必須自己實現(xiàn)訪問同步。一種解決方法是在創(chuàng)建List時構(gòu)造一個同步的List:
List list = Collections.synchronizedList(new LinkedList(…));
LinkedList的具體實現(xiàn)請參考這里
Vector與ArrayList相似,但是Vector是同步的。所以說Vector是線程安全的動態(tài)數(shù)組。它的操作與ArrayList幾乎一樣。
Vector的具體實現(xiàn)請參考這里
StackStack繼承自Vector,實現(xiàn)一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop 方法,還有peek方法得到棧頂?shù)脑兀琫mpty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創(chuàng)建后是空棧。
Stack的具體實現(xiàn)請參考這里
SetSet接口繼承了Collection接口。Set集合中不能包含重復的元素,每個元素必須是唯一的。你只需將元素加入set中,重復的元素會自動移除。有三種常見的Set實現(xiàn)——HashSet, TreeSet和LinkedHashSet。如果你需要一個訪問快速的Set,你應(yīng)該使用HashSet;當你需要一個排序的Set,你應(yīng)該使用TreeSet;當你需要記錄下插入時的順序時,你應(yīng)該使用LinedHashSet。
HashSetHashSet是是基于 HashMap 實現(xiàn)的,底層采用 HashMap 來保存元素,所以它不保證set 的迭代順序;特別是它不保證該順序恒久不變。add()、remove()以及contains()等方法都是復雜度為O(1)的方法。由于HashMap中key不可重復,所以HashSet元素不可重復。可以存儲null元素,是線程不安全的。
TreeSetTreeSet是一個有序集,基于TreeMap實現(xiàn),是線程不安全的。
TreeSet底層采用TreeMap存儲,構(gòu)造器啟動時新建TreeMap。TreeSet存儲元素實際為TreeMap存儲的鍵值對為
TreeSet支持兩種兩種排序方式,通過不同構(gòu)造器調(diào)用實現(xiàn)
自然排序:
public TreeSet() { // 新建TreeMap,自然排序 this(new TreeMap()); }
Comparator排序:
public TreeSet(Comparator super E> comparator) { // 新建TreeMap,傳入自定義比較器comparator this(new TreeMap<>(comparator)); }
TreeSet支持正向/反向迭代器遍歷和foreach遍歷
// 順序TreeSet:迭代器實現(xiàn) Iterator iter = set.iterator(); while (iter.hasNext()) { System.out.println(iter.next()); } // 順序遍歷TreeSet:foreach實現(xiàn) for (Integer i : set) { System.out.println(i); } // 逆序遍歷TreeSet:反向迭代器實現(xiàn) Iterator iter1 = set.descendingIterator(); while (iter1.hasNext()) { System.out.println(iter1.next()); }LinkedHashSet
LinkedHashSet介于HashSet和TreeSet之間。哈希表和鏈接列表實現(xiàn)。基本方法的復雜度為O(1)。
LinkedHashSet 是 Set 的一個具體實現(xiàn),其維護著一個運行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序可為插入順序或是訪問順序。
LinkedHashSet 繼承于 HashSet,并且其內(nèi)部是通過 LinkedHashMap 來實現(xiàn)的。有點類似于我們之前說的LinkedHashMap 其內(nèi)部是基于 Hashmap 實現(xiàn)的一樣。
如果我們需要迭代的順序為插入順序或者訪問順序,那么 LinkedHashSet 是需要你首先考慮的。
LinkedHashSet 底層使用 LinkedHashMap 來保存所有元素,因為繼承于 HashSet,所有的方法操作上又與 HashSet 相同,因此 LinkedHashSet 的實現(xiàn)上非常簡單,只提供了四個構(gòu)造方法,并通過傳遞一個標識參數(shù),調(diào)用父類的構(gòu)造器,底層構(gòu)造一個 LinkedHashMap 來實現(xiàn),在相關(guān)操作上與父類 HashSet 的操作相同,直接調(diào)用父類 HashSet 的方法即可。
package java.util; public class LinkedHashSetextends HashSet implements Set , Cloneable, java.io.Serializable { private static final long serialVersionUID = -2851667679971038690L; /** * 構(gòu)造一個帶有指定初始容量和加載因子的空鏈表哈希set。 * * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個有指定初始容量和加載因子的LinkedHashMap實例。 * @param initialCapacity 初始容量。 * @param loadFactor 加載因子。 */ public LinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor, true); } /** * 構(gòu)造一個指定初始容量和默認加載因子0.75的新鏈表哈希set。 * * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個指定初始容量和默認加載因子0.75的LinkedHashMap實例。 * @param initialCapacity 初始容量。 */ public LinkedHashSet(int initialCapacity) { super(initialCapacity, .75f, true); } /** * 構(gòu)造一個默認初始容量16和加載因子0.75的新鏈表哈希set。 * * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個默認初始容量16和加載因子0.75的LinkedHashMap實例。 */ public LinkedHashSet() { super(16, .75f, true); } /** * 構(gòu)造一個與指定collection中的元素相同的新鏈表哈希set。 * * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個足以包含指定collection * 中所有元素的初始容量和加載因子為0.75的LinkedHashMap實例。 * @param c 其中的元素將存放在此set中的collection。 */ public LinkedHashSet(Collection extends E> c) { super(Math.max(2*c.size(), 11), .75f, true); addAll(c); } @Override public Spliterator spliterator() { return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED); } }
通過觀察HashMap的源碼我們可以發(fā)現(xiàn):
Hash Map的前三個構(gòu)造函數(shù),即訪問權(quán)限為public類型的構(gòu)造函數(shù)均是以HashMap作為實現(xiàn)。而以LinkedHashMap作為實現(xiàn)的構(gòu)造函數(shù)的訪問權(quán)限是默認訪問權(quán)限,即包內(nèi)訪問權(quán)限。
即:在java編程中,通過new創(chuàng)建的HashSet對象均是以HashMap作為實現(xiàn)基礎(chǔ)。只有在jdk中java.util包內(nèi)的源代碼才可能創(chuàng)建以LinkedHashMap作為實現(xiàn)的HashSet(LinkedHashSet就是通過封裝一個以LinkedHashMap為實現(xiàn)的HashSet來實現(xiàn)的)。
只有包含三個參數(shù)的構(gòu)造函數(shù)才是采用的LinkedHashMap作為實現(xiàn)。
MapMap與List、Set接口不同,它是由一系列鍵值對組成的集合,提供了key到Value的映射。同時它也沒有繼承Collection。在Map中它保證了key與value之間的一一對應(yīng)關(guān)系。也就是說一個key對應(yīng)一個value,所以它不能存在相同的key值,當然value值可以相同。key可以為空,但是只允許出現(xiàn)一個null。它的主要實現(xiàn)類有HashMap、HashTable、LinkedHashMap、TreeMap。
HashMapHashMap 是 Map 的一個實現(xiàn)類,它代表的是一種鍵值對的數(shù)據(jù)存儲形式。
大多數(shù)情況下可以直接定位到它的值,因而具有很快的訪問速度,但遍歷順序卻是不確定的。
HashMap最多只允許一條記錄的鍵為null,允許多條記錄的值為null。遇到key為null的時候,調(diào)用putForNullKey方法進行處理,而對value沒有處理。不保證有序(比如插入的順序)、也不保證序不隨時間變化。
jdk 8 之前,其內(nèi)部是由數(shù)組+鏈表來實現(xiàn)的,而 jdk 8 對于鏈表長度超過 8 的鏈表將轉(zhuǎn)儲為紅黑樹。
HashMap非線程安全,即任一時刻可以有多個線程同時寫HashMap,可能會導致數(shù)據(jù)的不一致。如果需要滿足線程安全,可以用 Collections的synchronizedMap方法使HashMap具有線程安全的能力,或者使用ConcurrentHashMap。
hash數(shù)組的默認大小是16,而且大小一定是2的指數(shù)
HashMap的具體實現(xiàn)請參考這里
HashTableHashtable和HashMap一樣也是散列表,存儲元素也是鍵值對,底層實現(xiàn)是一個Entry數(shù)組+鏈表。Hashtable繼承于Dictionary類(Dictionary類聲明了操作鍵值對的接口方法),實現(xiàn)Map接口(定義鍵值對接口)。HashTable是線程安全的,它的大部分類都被synchronized關(guān)鍵字修飾。key和value都不可為null。
hash數(shù)組默認大小是11,擴充方式是old*2+1
LinkedHashMapLinkedHashMap繼承自HashMap實現(xiàn)了Map接口。基本實現(xiàn)同HashMap一樣(底層基于數(shù)組+鏈表+紅黑樹實現(xiàn)),不同之處在于LinkedHashMap保證了迭代的有序性。其內(nèi)部維護了一個雙向鏈表,解決了 HashMap不能隨時保持遍歷順序和插入順序一致的問題。
除此之外,LinkedHashMap對訪問順序也提供了相關(guān)支持。在一些場景下,該特性很有用,比如緩存。
在實現(xiàn)上,LinkedHashMap很多方法直接繼承自HashMap,僅為維護雙向鏈表覆寫了部分方法。
默認情況下,LinkedHashMap的迭代順序是按照插入節(jié)點的順序。也可以通過改變accessOrder參數(shù)的值,使得其遍歷順序按照訪問順序輸出。
LinkedHashMap的具體實現(xiàn)請參考這里
TreeMapTreeMap繼承自AbstractMap抽象類,并實現(xiàn)了SortedMap接口,如下圖所示:
[圖片上傳失敗...(image-fd7a40-1530872801038)]
TreeMap集合是基于紅黑樹(Red-Black tree)的 NavigableMap實現(xiàn)。該集合最重要的特點就是可排序,該映射根據(jù)其鍵的自然順序進行排序,或者根據(jù)創(chuàng)建映射時提供的 Comparator 進行排序,具體取決于使用的構(gòu)造方法。
關(guān)于集合的常見問題 List和Map的區(qū)別都是Java常用的容器,都是接口。不同的是List存儲的是單列的集合,Map存儲的是key-value鍵值對的集合。List中允許出現(xiàn)重復元素,Map中不允許key重復。List集合是有序的(儲存有序),Map集合是無序的(存儲無序)
Set中的元素不能重復,如何實現(xiàn)?Set大多都用的Map接口的實現(xiàn)類來實現(xiàn)的(HashSet基于HashMap實現(xiàn),TreeSet基于TreeMap實現(xiàn),LinkedHashSet基于LinkedHashMap實現(xiàn))
在HashMap中通過如下實現(xiàn)來保證key值唯一
// 1. 如果key 相等 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; // 2. 修改對應(yīng)的value if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; }
添加元素的時候,如果key(也對應(yīng)的Set集合的元素)相等,那么則修改value值。而在Set集合中,value值僅僅是一個Object對象罷了(該對象對Set本身而言是無用的)。
也就是說:Set集合如果添加的元素相同時,是根本沒有插入的(僅修改了一個無用的value值)。從源碼(HashMap)中也看出來,==和equals()方法都有使用!
Vector和ArrayList相同點:
這兩個類都實現(xiàn)了List接口,他們都是有序的集合(儲存有序),底層都用數(shù)組實現(xiàn)。可以通過索引來獲取某個元素。允許元素重復和出現(xiàn)null值。ArrayList和Vector的迭代器實現(xiàn)都是fail-fast的。
不同點:
vector是線程同步的,所以它也是線程安全的,而arraylist是線程異步的,是不安全的。如果不考慮到線程的安全因素,一般用arraylist效率比較高。
擴容時,arraylist擴容1.5倍,vector擴容2倍(或者擴容指定的大小)
ArrayList 和Vector是采用數(shù)組方式存儲數(shù)據(jù),此數(shù)組元素數(shù)大于實際存儲的數(shù)據(jù)以便增加和插入元素,都允許直接序號索引元素,但是插入數(shù)據(jù)要設(shè)計到數(shù)組元素移動等內(nèi)存操作,所以索引數(shù)據(jù)快插入數(shù)據(jù)慢,Vector由于使用了synchronized方法(線程安全)所以性能上比ArrayList要差,LinkedList使用雙向鏈表實現(xiàn)存儲,按序號索引數(shù)據(jù)需要進行向前或向后遍歷,但是插入數(shù)據(jù)時只需要記錄本項的前后項即可,所以插入數(shù)度較快!
Aarraylist和LinkedlistArrayList是基于數(shù)組實現(xiàn)的,LinkedList基于雙向鏈表實現(xiàn)的。
ArrayList它支持以下標位置進行索引出對應(yīng)的元素(隨機訪問),而LinkedList則需要遍歷整個鏈表來獲取對應(yīng)的元素。因此一般來說ArrayList的訪問速度是要比LinkedList要快的
ArrayList由于是數(shù)組,對于刪除和修改而言消耗是比較大(復制和移動數(shù)組實現(xiàn)),LinkedList是雙向鏈表刪除和修改只需要修改對應(yīng)的指針即可,消耗是很小的。因此一般來說LinkedList的增刪速度是要比ArrayList要快的
LinkedList比ArrayList消耗更多的內(nèi)存,因為LinkedList中的每個節(jié)點存儲了前后節(jié)點的引用。
對于增加/刪除元素操作
如果增刪都是在末尾來操作(每次調(diào)用的都是remove()和add()),此時ArrayList就不需要移動和復制數(shù)組來進行操作了。如果數(shù)據(jù)量有百萬級的時,速度是會比LinkedList要快的。
如果刪除操作的位置是在中間。由于LinkedList的消耗主要是在遍歷上,ArrayList的消耗主要是在移動和復制上(底層調(diào)用的是arraycopy()方法,是native方法)。
LinkedList的遍歷速度是要慢于ArrayList的復制移動速度的
如果數(shù)據(jù)量有百萬級的時,還是ArrayList要快。
ArrayList、HashMap、TreeMap和HashTable類提供對元素的隨機訪問。
Enumeration和Iterator接口的區(qū)別Enumeration的速度是Iterator的兩倍,也使用更少的內(nèi)存。Enumeration是非常基礎(chǔ)的,也滿足了基礎(chǔ)的需要。但是,與Enumeration相比,Iterator更加安全,因為當一個集合正在被遍歷的時候,它會阻止其它線程去修改集合。
Iterator的方法名比Enumeration更科學
Iterator有fail-fast機制,比Enumeration更安全
Iterator能夠刪除元素,Enumeration并不能刪除元素
我們可以使用Iterator來遍歷Set和List集合,而ListIterator只能遍歷List。
Iterator只可以向前遍歷,而LIstIterator可以雙向遍歷。
ListIterator從Iterator接口繼承,然后添加了一些額外的功能,比如添加一個元素、替換一個元素、獲取前面或后面元素的索引位置。
需要同時重寫該類的hashCode()方法和它的equals()方法。
從源碼可以得知,在插入元素的時候是先算出該對象的hashCode。如果hashcode相等話的。那么表明該對象是存儲在同一個位置上的。
如果調(diào)用equals()方法,兩個key相同,則替換元素
如果調(diào)用equals()方法,兩個key不相同,則說明該hashCode僅僅是碰巧相同,此時是散列沖突,將新增的元素放在桶子上
重寫了equals()方法,就要重寫hashCode()的方法。因為equals()認定了這兩個對象相同,而同一個對象調(diào)用hashCode()方法時,是應(yīng)該返回相同的值的!
HashSet與HashMapHashSet 實現(xiàn)了 Set 接口,它不允許集合中有重復的值,當我們提到 HashSet 時,第一件事情就是在將對象存儲在 HashSet 之前,要先確保對象重寫 equals()和 hashCode()方法,這樣才能比較對象的值是否相等,以確保set中沒有儲存相等的對象。如果我們沒有重寫這兩個方法,將會使用這個方法的默認實現(xiàn)。
public boolean add(Object o)方法用來在 Set 中添加元素,當元素值重復時則會立即返回 false,如果成功添加的話會返回 true。
HashMap 實現(xiàn)了 Map 接口,Map 接口對鍵值對進行映射。Map 中不允許重復的鍵。Map 接口有兩個基本的實現(xiàn),HashMap 和 TreeMap。TreeMap 保存了對象的排列次序,而 HashMap 則不能。HashMap 允許鍵和值為 null。HashMap 是非 synchronized 的,但 collection 框架提供方法能保證 HashMap synchronized,這樣多個線程同時訪問 HashMap 時,能保證只有一個線程更改 Map。
public Object put(Object Key,Object value)方法用來將元素添加到 map 中。
HashMap | HashSet |
---|---|
HashMap實現(xiàn)了Map接口 | HashSet實現(xiàn)了Set接口 |
HashMap儲存鍵值對 | HashSet僅僅存儲對象 |
使用put()方法將元素放入map中 | 使用add()方法將元素放入set中 |
HashMap中使用鍵對象來計算hashcode值 | HashSet使用成員對象來計算hashcode值,對于兩個對象來說hashcode可能相同,所以equals()方法用來判斷對象的相等性,如果兩個對象不同的話,那么返回false |
相同點:
儲存結(jié)構(gòu)和實現(xiàn)基本相同,都是是實現(xiàn)的Map接口
不同點:
HashTable是同步的,HashMap是非同步的,需要同步的時候可以ConcurrentHashMap方法
HashMap允許為null,HashTable不允許為null
繼承不同,HashMap繼承的是AbstractMap,HashTable繼承的是Dictionary
HashMap提供對key的Set進行遍歷,因此它是fail-fast的,但HashTable提供對key的Enumeration進行遍歷,它不支持fail-fast。
HashTable是一個遺留類,如果需要保證線程安全推薦使用CocurrentHashMap
HashMap與TreeMapHashMap通過hashcode對其內(nèi)容進行快速查找,而TreeMap中所有的元素都保持著某種固定的順序,如果你需要得到一個有序的結(jié)果你就應(yīng)該使用TreeMap(HashMap中元素的排列順序是不固定的)。HashMap中元素的排列順序是不固定的)。
在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那么TreeMap會更好。使用HashMap要求添加的鍵類明確定義了hashCode()和 equals()的實現(xiàn)。 這個TreeMap沒有調(diào)優(yōu)選項,因為該樹總處于平衡狀態(tài)。
集合框架中的泛型有什么優(yōu)點?Java1.5引入了泛型,所有的集合接口和實現(xiàn)都大量地使用它。泛型允許我們?yōu)榧咸峁┮粋€可以容納的對象類型,因此,如果你添加其它類型的任何元素,它會在編譯時報錯。這避免了在運行時出現(xiàn)ClassCastException,因為你將會在編譯時得到報錯信息。泛型也使得代碼整潔,我們不需要使用顯式轉(zhuǎn)換和instanceOf操作符。它也給運行時帶來好處,因為不會產(chǎn)生類型檢查的字節(jié)碼指令。
comparable 和 comparator的不同之處?comparable接口實際上是出自java.lang包
它有一個 compareTo(Object obj)方法來將objects排序
comparator接口實際上是出自 java.util 包
它有一個compare(Object obj1, Object obj2)方法來將objects排序
Vector, Hashtable, Properties 和 Stack 都是同步的類,所以它們都線程安全的,可以被使用在多線程環(huán)境中
使用Collections.synchronizedList(list)) 方法,可以保證list類是線程安全的
使用java.util.Collections.synchronizedSet()方法可以保證set類是線程安全的。
TreeSet要求存放的對象所屬的類必須實現(xiàn)Comparable接口,該接口提供了比較元素的compareTo()方法,當插入元素時會回調(diào)該方法比較元素的大小。
TreeMap要求存放的鍵值對映射的鍵必須實現(xiàn)Comparable接口從而根據(jù)鍵對元素進行排序。
Collections工具類的sort方法有兩種重載的形式,第一種要求傳入的待排序容器中存放的對象比較實現(xiàn)Comparable接口以實現(xiàn)元素的比較;第二種不強制性的要求容器中的元素必須可比較,但是要求傳入第二個參數(shù),參數(shù)是Comparator接口的子類型(需要重寫compare方法實現(xiàn)元素的比較),相當于一個臨時定義的排序規(guī)則,其實就是通過接口注入比較元素大小的算法,也是對回調(diào)模式的應(yīng)用(Java中對函數(shù)式編程的支持)。
什么是Java優(yōu)先級隊列?Java PriorityQueue是一個數(shù)據(jù)結(jié)構(gòu),它是Java集合框架的一部分。 它是一個隊列的實現(xiàn),其中元素的順序?qū)⒏鶕?jù)每個元素的優(yōu)先級來決定。 實例化PriorityQueue時,可以在構(gòu)造函數(shù)中提供比較器。 該比較器將決定PriorityQueue集合實例中元素的排序順序。
Java hashCode()和equals()方法。equals()方法用于確定兩個Java對象的相等性。 當我們有一個自定義類時,我們需要重寫equals()方法并提供一個實現(xiàn),以便它可以用來找到它的兩個實例之間的相等性。 通過Java規(guī)范,equals()和hashCode()之間有一個契約。 它說,“如果兩個對象相等,即obj1.equals(obj2)為true,那么obj1.hashCode()和obj2.hashCode()必須返回相同的整數(shù)”
無論何時我們選擇重寫equals(),我們都必須重寫hashCode()方法。 hashCode()用于計算位置存儲區(qū)和key。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/71493.html
摘要:下面是一些常見的理解性問題,每一個問題盡量用圖或代碼去描述。內(nèi)容全部來自,包括基本語法數(shù)組集合類泛型面向?qū)ο罄厥债惓?刂戚斎胼敵龊蛢?nèi)存。不斷更新,歡迎大家提出有趣味的問題和意見。 程序員經(jīng)常可以通過搜索或者記憶來完成代碼,但是許多時候并不真正理解為什么那樣寫。也就是說,有一定經(jīng)驗的程序員不會犯一些低級的語法錯誤,但是因為不深入理解有可能造成一些高級錯誤,比如說運行無效率,代碼難De...
摘要:編程思想第版這本書要常讀,初學者可以快速概覽,中等程序員可以深入看看,老鳥還可以用之回顧的體系。以下視頻整理自慕課網(wǎng)工程師路徑相關(guān)免費課程。 我自己總結(jié)的Java學習的系統(tǒng)知識點以及面試問題,目前已經(jīng)開源,會一直完善下去,歡迎建議和指導歡迎Star: https://github.com/Snailclimb/Java-Guide 筆者建議初學者學習Java的方式:看書+視頻+實踐(初...
摘要:動畫占用大量內(nèi)存,如何優(yōu)化使用動畫的注意事項有哪些問題這個問題主要出現(xiàn)在幀動畫中,當圖片數(shù)量較多且圖片較大時就極易出現(xiàn),這個在實際開發(fā)中要尤其注意,盡量避免使用幀動畫。 目錄介紹 4.0.0.1 Android中有哪幾種類型的動畫,屬性動畫和補間動畫有何區(qū)別?補間動畫和屬性動畫常用的有哪些? 4.0.0.2 View動畫為何不能真正改變View的位置?而屬性動畫為何可以?屬性動畫是如...
摘要:中的詳解必修個多線程問題總結(jié)個多線程問題總結(jié)有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升開源的運行原理從虛擬機工作流程看運行原理。 自己實現(xiàn)集合框架 (三): 單鏈表的實現(xiàn) 自己實現(xiàn)集合框架 (三): 單鏈表的實現(xiàn) 基于 POI 封裝 ExcelUtil 精簡的 Excel 導入導出 由于 poi 本身只是針對于 ...
摘要:目錄介紹問題匯總具體問題好消息博客筆記大匯總年月到至今,包括基礎(chǔ)及深入知識點,技術(shù)博客,學習筆記等等,還包括平時開發(fā)中遇到的匯總,當然也在工作之余收集了大量的面試題,長期更新維護并且修正,持續(xù)完善開源的文件是格式的同時也開源了生活博客,從年 目錄介紹 00.Java問題匯總 01.具體問題 好消息 博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識點,Android技...
閱讀 1019·2022-07-19 10:19
閱讀 1794·2021-09-02 15:15
閱讀 1007·2019-08-30 15:53
閱讀 2653·2019-08-30 13:45
閱讀 2651·2019-08-26 13:57
閱讀 1983·2019-08-26 12:13
閱讀 1006·2019-08-26 10:55
閱讀 545·2019-08-26 10:46