學習java的同學注意了?。。?nbsp;學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986 我們一起學Java!
下面要開始java中相關集合框架的學習啦。
Are you ready?Let's go~~
今天要講解的Java中的集合框架。
1) 首先查看jdk中Collection類的源碼后會發現如下內容:
1234567 ... *
@see
AbstractCollection
*
@since
1.2
*/
public
interface
Collection<e>
extends
Iterable<e> {
// Query Operations
</e></e>
通過查看可以發現Collection是一個接口類,其繼承了java迭代接口Iterable。
眾所周知在我們使用Java中的類的存儲的時候經常會使用一些容器,鏈表的概念,本文將徹底幫您弄清鏈表的各種概念和模型?。。?!
注意理解哦~~~ 大致框架如下:
Collection接口有兩個主要的子接口List和Set,注意Map不是Collection的子接口哦這個要牢記。
Collection中可以存儲的元素間無序,可以重復組各 自獨立的元素, 即其內的每個位置僅持有一個元素,同時允許有多個null元素對象。
Collection接口中的方法如下:
1)List接口
List接口對Collection進行了簡單的擴充
查看List接口的源碼會發現:
12345678910111213 ...<br> *
@see
AbstractList
*
@see
AbstractSequentialList
*
@since
1.2
*/
public
interface
List<E>
extends
Collection<E> {
// Query Operations
/**
* Returns the number of elements in
this
list. If
this
list contains
* more than <tt>Integer.MAX_VALUE</tt> elements, returns
* <tt>Integer.MAX_VALUE</tt>.
<br> ...
這里也就知道為什么Collection接口時List接口的父接口了吧。
List接口中的元素的特點為:
List中存儲的元素實現類排序,而且可以重復的存儲相關元素。
同時List接口又有兩個常用的實現類ArrayList和LinkedList
1)ArrayList:
ArrayList數組線性表的特點為:類似數組的形式進行存儲,因此它的隨機訪問速度極快。
ArrayList數組線性表的缺點為:不適合于在線性表中間需要頻繁進行插入和刪除操作。因為每次插入和刪除都需要移動數組中的元素。
可以這樣理解ArrayList就是基于數組的一個線性表,只不過數組的長度可以動態改變而已。
對于ArrayList的詳細使用信息以及創建的過程可以查看jdk中ArrayList的源碼,這里不做過多的講解。
對于使用ArrayList的開發者而言,下面幾點內容一定要注意啦,尤其找工作面試的時候經常會被問到。
注意啦?。。。。。。。?/p>
a.如果在初始化ArrayList的時候沒有指定初始化長度的話,默認的長度為10.
123456 /**
* Constructs an empty list with an initial capacity of ten.
*/
public
ArrayList() {
this
(
10
);
}
b.ArrayList在增加新元素的時候如果超過了原始的容量的話,ArrayList擴容ensureCapacity的方案為“原始容量*3/2+1"哦。
12345678910111213141516171819 /**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public
void
ensureCapacity(
int
minCapacity) {
modCount++;
int
oldCapacity = elementData.length;
if
(minCapacity > oldCapacity) {
Object oldData[] = elementData;
int
newCapacity = (oldCapacity *
3
)/
2
+
1
;
if
(newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
c.ArrayList是線程不安全的,在多線程的情況下不要使用。
如果一定在多線程使用List的,您可以使用Vector,因為Vector和ArrayList基本一致,區別在于Vector中的絕大部分方法都
使用了同步關鍵字修飾,這樣在多線程的情況下不會出現并發錯誤哦,還有就是它們的擴容方案不同,ArrayList是通過原始
容量*3/2+1,而Vector是允許設置默認的增長長度,Vector的默認擴容方式為原來的2倍。
切記Vector是ArrayList的多線程的一個替代品。
d.ArrayList實現遍歷的幾種方法
1234567891011121314151617181920212223242526272829303132333435363738394041 package
com.yonyou.test;
import
java.util.ArrayList;
import
java.util.Iterator;
import
java.util.List;
/**
* 測試類
* @author 小浩
* @創建日期 2015-3-2
*/
public
class
Test{
public
static
void
main(String[] args) {
List<String> list=
new
ArrayList<String>();
list.add(
"Hello"
);
list.add(
"World"
);
list.add(
"HAHAHAHA"
);
//第一種遍歷方法使用foreach遍歷List
for
(String str : list) {
//也可以改寫for(int i=0;i<list.size();i++)這種形式
System.out.PRintln(str);
}
//第二種遍歷,把鏈表變為數組相關的內容進行遍歷
String[] strArray=
new
String[list.size()];
list.toArray(strArray);
for
(
int
i=
0
;i<strArray.length;i++)
//這里也可以改寫為foreach(String str:strArray)這種形式
{
System.out.println(strArray[i]);
}
//第三種遍歷 使用迭代器進行相關遍歷
Iterator<String> ite=list.iterator();
while
(ite.hasNext())
{
System.out.println(ite.next());
}
}
}
尼瑪,以上四點面試經常會被問到的。到時候死翹翹別說哥沒告訴你。
2)LinkedList
LinkedList的鏈式線性表的特點為: 適合于在鏈表中間需要頻繁進行插入和刪除操作。
LinkedList的鏈式線性表的缺點為: 隨機訪問速度較慢。查找一個元素需要從頭開始一個一個的找。速度你懂的。
可以這樣理解LinkedList就是一種雙向循環鏈表的鏈式線性表,只不過存儲的結構使用的是鏈式表而已。
對于LinkedList的詳細使用信息以及創建的過程可以查看jdk中LinkedList的源碼,這里不做過多的講解。
對于使用LinkedList的開發者而言,下面幾點內容一定要注意啦,尤其找工作面試的過程時候經常會被問到。
注意啦?。。。。。。?!
a.LinkedList和ArrayList的區別和聯系
ArrayList數組線性表的特點為:類似數組的形式進行存儲,因此它的隨機訪問速度極快。
ArrayList數組線性表的缺點為:不適合于在線性表中間需要頻繁進行插入和刪除操作。因為每次插入和刪除都需要移動數組中的元素。
LinkedList的鏈式線性表的特點為: 適合于在鏈表中間需要頻繁進行插入和刪除操作。
LinkedList的鏈式線性表的缺點為: 隨機訪問速度較慢。查找一個元素需要從頭開始一個一個的找。速度你懂的。
b.LinkedList的內部實現
對于這個問題,你最好看一下jdk中LinkedList的源碼。這樣你會醍醐灌頂的。
這里我大致說一下:
LinkedList的內部是基于雙向循環鏈表的結構來實現的。在LinkedList中有一個類似于c語言中結構體的Entry內部類。
在Entry的內部類中包含了前一個元素的地址引用和后一個元素的地址引用類似于c語言中指針。
c.LinkedList不是線程安全的
注意LinkedList和ArrayList一樣也不是線程安全的,如果在對線程下面訪問可以自己重寫LinkedList
然后在需要同步的方法上面加上同步關鍵字synchronized
d.LinkedList的遍歷方法
123456789101112131415161718192021222324252627282930313233343536 package
com.yonyou.test;
import
java.util.LinkedList;
import
java.util.List;
/**
* 測試類
* @author 小浩
* @創建日期 2015-3-2
*/
public
class
Test{
public
static
void
main(String[] args) {
List<String> list=
new
LinkedList<String>();
list.add(
"Hello"
);
list.add(
"World"
);
list.add(
"龍不吟,虎不嘯"
);
//LinkedList遍歷的第一種方式使用數組的方式
String[] strArray=
new
String[list.size()];
list.toArray(strArray);
for
(String str:strArray)
{
System.out.println(str);
}
//LinkedList遍歷的第二種方式
for
(String str:list)
{
System.out.println(str);
}
//至于還是否有其它遍歷方式,我沒查,感興趣自己研究研究
}
}
e.LinkedList可以被當做堆棧來使用
由于LinkedList實現了接口Dueue,所以LinkedList可以被當做堆棧來使用,這個你自己研究吧。
2)Set接口
Set接口也是Collection接口的一個常用子接口。
查看Set接口的源碼你會發現:
12345678910 *
@see
Collections#EMPTY_SET
*
@since
1.2
*/
public
interface
Set<E>
extends
Collection<E> {
// Query Operations
/**
* Returns the number of elements in
this
set (its cardinality). If
this
* set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
這里就自然而然的知道Set接口是Collection接口的子接口了吧。
Set接口區別于List接口的特點在于:
Set中的元素實現了不重復,有點象集合的概念,無序,不允許有重復的元素,最多允許有一個null元素對象。
需要注意的是:雖然Set中元素沒有順序,但是元素在set中的位置是有由該元素的HashCode決定的,其具體位置其實是固定的。
查看jdk的源碼會發現下面的內容
1234567891011 ...<br> *
@see
Collections#EMPTY_SET
*
@since
1.2
*/
public
interface
Set<E>
extends
Collection<E> {
// Query Operations
/**
* Returns the number of elements in
this
set (its cardinality). If
this
* set contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
<br> ...
在這里也會看到set接口時Collection接口的子接口吧~哈
此外需要說明一點,在set接口中的不重復是由特殊要求的。
舉一個例子:對象A和對象B,本來是不同的兩個對象,正常情況下它們是能夠放入到Set里面的,但是
如果對象A和B的都重寫了hashcode和equals方法,并且重寫后的hashcode和equals方法是相同的話。那么A和B是不能同時放入到
Set集合中去的,也就是Set集合中的去重和hashcode與equals方法直接相關。
為了更好的理解,請看下面的例子:
12345678910111213141516171819202122 package
com.yonyou.test;
import
java.util.HashSet;
import
java.util.Set;
/**
* 測試類
* @author 小浩
* @創建日期 2015-3-2
*/
public
class
Test{
public
static
void
main(String[] args) {
Set<String> set=
new
HashSet<String>();
set.add(
"Hello"
);
set.add(
"world"
);
set.add(
"Hello"
);
System.out.println(
"集合的尺寸為:"
+set.size());
System.out.println(
"集合中的元素為:"
+set.toString());
}
}
由于String類中重寫了hashcode和equals方法,所以這里的第二個Hello是加不進去的哦。
Set接口的常見實現類有HashSet,LinedHashSet和TreeSet這三個。下面我們將分別講解這三個類。
1)HashSet
HashSet是Set接口的最常見的實現類了。其底層是基于Hash算法進行存儲相關元素的。
下面是HashSet的部分源碼:
1234567 /**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public
HashSet() {
map =
new
HashMap<E,Object>();
}
你看到了什么,沒錯,對于HashSet的底層就是基于HashMap來實現的哦。
我們都知道在HashMap中的key是不允許重復的,你換個角度看看,那不就是說Set集合嗎?
這里唯一一個需要處理的就是那個Map的value弄成一個固定值即可。
看來一切水到渠成啊~哈哈~這里的就是Map中的Key。
對于HashMap和Hash算法的講解會在下面出現,先別著急,下面繼續講解HashSet。
下面講解一下HashSet使用和理解中容易出現的誤區:
a.HashSet中存放null值
HashSet中時允許出入null值的,但是在HashSet中僅僅能夠存入一個null值哦。
b.HashSet中存儲元素的位置是固定的
HashSet中存儲的元素的是無序的,這個沒什么好說的,但是由于HashSet底層是基于Hash算法實現的,使用了hashcode,
所以HashSet中相應的元素的位置是固定的哦。
c.遍歷HashSet的幾種方法
具體的方法不說了,請看下面的代碼:
12345678910111213141516171819202122232425262728293031323334353637383940 package
com.yonyou.test;
import
java.util.HashSet;
import
java.util.Iterator;
import
java.util.Set;
/**
* 測試類
* @author 小浩
* @創建日期 2015-3-2
*/
public
class
Test{
public
static
void
main(String[] args) {
Set<String> set=
new
HashSet<String>();
set.add(
"Hello"
);
set.add(
"world"
);
set.add(
"Hello"
);
//遍歷集合的第一種方法,使用數組的方法
String[] strArray=
new
String[set.size()];
strArray=set.toArray(strArray);
for
(String str:strArray)
//此處也可以使用for(int i=0;i<strArray.length;i++)
{
System.out.println(str);
}
//遍歷集合的第二中方法,使用set集合直接遍歷
for
(String str:set)
{
System.out.println(str);
}
//遍歷集合的第三種方法,使用iterator迭代器的方法
Iterator<String> iterator=set.iterator();
while
(iterator.hasNext())
{
System.out.println(iterator.next());
}
}
}
2)LinkHashSet
LinkHashSet不僅是Set接口的子接口而且還是上面HashSet接口的子接口。
查看LinkedHashSet的部分源碼如下:
12345678910111213 ...<br> *
@see
Hashtable
*
@since
1.4
*/
public
class
LinkedHashSet<E>
extends
HashSet<E>
implements
Set<E>, Cloneable, java.io.Serializable {
private
static
final
long
serialVersionUID = -2851667679971038690L;
/**
* Constructs a
new
, empty linked hash set with the specified initial
<br> ...
這里就可以發現Set接口時HashSet接口的一個子接口了吧~
通過查看LinkedHashSet的源碼可以發現,其底層是基于LinkedHashMap來實現的哦。
對于LinkedHashSet而言,它和HashSet主要區別在于LinkedHashSet中存儲的元素是在哈希算法的基礎上增加了
鏈式表的結構。
3)TreeSet
TreeSet是一種排序二叉樹。存入Set集合中的值,會按照值的大小進行相關的排序操作。底層算法是基于紅黑樹來實現的。
TreeSet和HashSet的主要區別在于TreeSet中的元素會按照相關的值進行排序~
TreeSet和HashSet的區別和聯系
1. HashSet是通過HashMap實現的,TreeSet是通過TreeMap實現的,只不過Set用的只是Map的key 2. Map的key和Set都有一個共同的特性就是集合的唯一性.TreeMap更是多了一個排序的功能. 3. hashCode和equal()是HashMap用的, 因為無需排序所以只需要關注定位和唯一性即可. a. hashCode是用來計算hash值的,hash值是用來確定hash表索引的. b. hash表中的一個索引處存放的是一張鏈表, 所以還要通過equal方法循環比較鏈上的每一個對象 才可以真正定位到鍵值對應的Entry. c. put時,如果hash表中沒定位到,就在鏈表前加一個Entry,如果定位到了,則更換Entry中的value,并返回舊value 4. 由于TreeMap需要排序,所以需要一個Comparator為鍵值進行大小比較.當然也是用Comparator定位的. a. Comparator可以在創建TreeMap時指定 b. 如果創建時沒有確定,那么就會使用key.compareTo()方法,這就要求key必須實現Comparable接口. c. TreeMap是使用Tree數據結構實現的,所以使用compare接口就可以完成定位了.
下面是一個使用TreeSet的實例:
123456789101112131415161718192021222324252627 package
com.yonyou.test;
import
java.util.Iterator;
import
java.util.TreeSet;
/**
* TreeSet測試類
* @author 小浩
* @創建日期 2015-4-3
*/
public
class
Test{
public
static
void
main(String[] args) {
//String實體類中實現Comparable接口,所以在初始化TreeSet的時候,
//無需傳入比較器
TreeSet<String> treeSet=
new
TreeSet<String>();
treeSet.add(
"d"
);
treeSet.add(
"c"
);
treeSet.add(
"b"
);
treeSet.add(
"a"
);
Iterator<String> iterator=treeSet.iterator();
while
(iterator.hasNext())
{
System.out.println(iterator.next());
}
}
}
3)Map接口
說到Map接口的話大家也許在熟悉不過了。Map接口實現的是一組Key-Value的鍵值對的組合。 Map中的每個成員方法由一個關鍵字(key)和一個值(value)構成。Map接口不直接繼承于Collection接口(需要注意啦),因為它包裝的是一組成對的“鍵-值”對象的集合,而且在Map接口的集合中也不能有重復的key出現,因為每個鍵只能與一個成員元素相對應。在我們的日常的開發項目中,我們無時無刻不在使用者Map接口及其實現類。Map有兩種比較常用的實現:HashMap和TreeMap等。HashMap也用到了哈希碼的算法,以便快速查找一個鍵,TreeMap則是對鍵按序存放,因此它便有一些擴展的方法,比如firstKey(),lastKey()等,你還可以從TreeMap中指定一個范圍以取得其子Map。鍵和值的關聯很簡單,用pub(Object key,Object value)方法即可將一個鍵與一個值對象相關聯。用get(Object key)可得到與此key對象所對應的值對象。
另外前邊已經說明了,Set接口的底層是基于Map接口實現的。Set中存儲的值,其實就是Map中的key,它們都是不允許重復的。
Map接口的部分源碼如下:
123456789 *
@see
Collection
*
@see
Set
*
@since
1.2
*/
public
interface
Map<K,V> {
// Query Operations
/**
* Returns the number of key-value mappings in
this
map. If the
為了更好的理解上面的內容,這里我們有必要簡單了解一下Hash算法的內容,由于篇幅限制,這里就不具體的講解Hash算法的實現過程了。如果感興趣的可以參考:http://www.cnblogs.com/xiohao/p/4389672.html
接下來我們講解Map接口的常見實現類HashMap、TreeMap、LinkedHashMap、Properties(繼承HashTable)以及老版本的HashTable等。
3)HashMap
HashMap實現了Map、CloneMap、Serializable三個接口,并且繼承自AbstractMap類。
HashMap基于hash數組實現,若key的hash值相同則使用鏈表方式進行保存。
新建一個HashMap時,默認的話會初始化一個大小為16,負載因子為0.75的空的HashMap
12345678910 /**
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* (16) and the default load factor (0.75).
*/
public
HashMap() {
this
.loadFactor = DEFAULT_LOAD_FACTOR;
threshold = (
int
)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table =
new
Entry[DEFAULT_INITIAL_CAPACITY];
init();
}
下面是一個HashMap中還存在一個內部類Entry,用于鏈表的存儲,如
1 static
class
Entry<K,V>
implements
Map.Entry<K,V> {<br>
final
K key;<br> V value;<br> Entry<K,V> next;<br>
final
int
hash;<br> ......
面代碼其實告訴我們Entry是一個結點,它持有下一個元素的引用,這樣就構成了一個鏈表。
那么,整體上來說HashMap底層就是使用這樣一個數據結構來實現的。
我們提到使用Hash,但是Hash值如何與元素的存儲建立關系呢?(Hash算法)
在數據結構課中我們學習過Hash的簡單算法,就是給你一個Hash因子,通過對該元素的hashCode簡單的求余,來實現對其快速的定位和索引。
在HashMap中有這樣的代碼:
/** * Returns index for hash code h. */ static int indexFor(int h, int length) { return h & (length-1); }/** * Returns index for hash code h. */static int indexFor(int h, int length) { return h & (length-1);}這個方法在HashMap中非常重要,凡是與查詢、添加、刪除有關的方法中都有調用該方法,為什么這么短的一個代碼使用率這么高?根據代碼注釋我們知道,這個方法是根據hashCode及當前table的長度(數組的長度,不是map的size)得到該元素應該存放的位置,或者在table中的索引。
現在我們需要看一下當數據量已經超過初始定義的負載因子時,HashMap如何處理?
在HashMap中當數據量很多時,并且已經達到了負載限度時,會重新做一次哈希,也就是說會再散列。調用的方法為resize(),并且java默認傳入的參數為2*table.length。先看一下JDK源碼:
/** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ 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); } /** * Transfers all entries from current table to newTable. */ 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); } } }看到這里我們會發現resize(再哈希)的工作量是不是很大啊。再哈希是重新建一個指定容量的數組,然后將每個元素重新計算它要放的位置,這個工作量確實是很大的。
這里就產生了一個很重要的問題,那就是怎么讓哈希表的分布比較均勻,也就是說怎么讓它即不會成為一個單鏈表(極限情況,每個key的hash值都集中到了一起),又不會使hash空間過大(導致內存浪費)?
上面兩個問題一個是解決了怎么計算hash值快速存取,一個是怎么實現再哈希,何時需要再哈希??焖俅嫒〉那疤崾窃胤植季鶆颍恢劣诩械揭稽c,再哈希是元素過于零散,導致不斷的重新構建表。
那么在第一個問題中我們看到了這樣一個代碼return h & (length-1);在第二個問題中我們說過內部調用傳入的值為2*table.length;并且默認情況下HashMap的大小為一個16的數字,除了默認構造提供大小為16的空間外,如果我們使用
public HashMap(int initialCapacity, float loadFactor)
上面的構造方法,我們會發現這樣的代碼:
// Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; …… table = new Entry[capacity];// Find a power of 2 >= initialCapacityint capacity = 1;while (capacity < initialCapacity) capacity <<= 1;……table = new Entry[capacity];也就是說當我們傳入1000時,它并沒有給我們構造一個容量為1000的哈希表,而是構建了一個容量為1024大小的哈希表。
從整體上我們發現一個問題,那就是無論什么情況HashMap中哈希表的容量總是2的n次方的一個數。并且有這樣一個公式:
當length=2^n時,hashcode & (length-1) == hashcode % length
也就是這一點驗證了第一個問題,hash索引值的計算方法其實就是對哈希因子求余。只有大小為2的n次方時,那樣的計算才成立,所以HashMap為我們維護了一個這樣大小的一個哈希表。(位運算速度比取模運算快的多)
c) HashMap的使用方法:
我在很多代碼中都用到了HashMap,原因是首先它符合存儲關聯數據的要求,其次它的存取速度快,這是一個選擇的問題。
比較重要的是HashMap的遍歷方法,在我的博客中有專門寫到HashMap的遍歷方法:http://blog.csdn.net/tsyj810883979/article/details/6746274
? LinkedHashMap的特點、實現機制及使用方法
a) LinkedHashMap的特點:
LinkedHashMap繼承自HashMap并且實現了Map接口。和HashMap一樣,LinkedHashMap允許key和value均為null。
于該數據結構和HashMap一樣使用到hash算法,因此它不能保證映射的順序,尤其是不能保證順序持久不變(再哈希)。
如果你想在多線程中使用,那么需要使用Collections.synchronizedMap方法進行外部同步。
LinkedHashMap與HashMap的不同之處在于,LinkedHashMap維護者運行于所有條目的雙重鏈接列表,此鏈接列表可以是插入順序或者訪問順序。
b) LinkedHashMap的實現機制:
無法總結下去,在網上看到這樣一篇文章:http://zhangshixi.iteye.com/blog/673789
感覺真的沒辦法總結下去了。
? HashMap與Hashtable的區別:
Hashtable實現Map接口,繼承自古老的Dictionary類,實現一個key-value的鍵值映射表。任何非空的(key-value)均可以放入其中。
區別主要有三點:
1. Hashtable是基于陳舊的Dictionary實現的,而HashMap是基于Java1.2引進的Map接口實現的;
2. Hashtable是線程安全的,而HashMap是非線程安全的,我們可以使用外部同步的方法解決這個問題。
3. HashMap可以允許你在列表中放一個key值為null的元素,并且可以有任意多value為null,而Hashtable不允許鍵或者值為null。
? WeakHashMap的特點:
我沒有使用過這個類。網摘:WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被GC回收。(后續使用后進行總結)
? Properties及TreeMap在后續內容里進行總結。
就先這樣吧,Java集合框架的講解就先到這里了啊~
學習Java的同學注意了?。?! 學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Java學習交流群,群號碼:523047986 我們一起學Java!
新聞熱點
疑難解答