從圖1中可以看到,Collection是集合繼承樹中最頂層的接口,幾乎所有的Java集合框架成員都繼承實(shí)現(xiàn)了Collection接口,或者與其有密切關(guān)系。Collection提供了關(guān)于集合的通用操作。Set接口和List接口都繼承了Collection接口,而Map接口沒有繼承Collection接口。因此,Set對(duì)象和List對(duì)象都可以調(diào)用Collection接口的方法,而Map對(duì)象則不可以。 下面我們對(duì)這三種類型接口的結(jié)構(gòu)加以說(shuō)明:Set有點(diǎn)類似數(shù)學(xué)中集合的定義,是無(wú)序的、沒有重復(fù)項(xiàng)目的集合。List是位置性集合,加進(jìn)清單的元素可以加在清單中特定位置或加到末尾,可以保存重復(fù)的元素。Map用于關(guān)鍵字/數(shù)值對(duì),其中關(guān)鍵字是數(shù)值的惟一標(biāo)識(shí)(不可重復(fù)),用戶可以按關(guān)鍵字存取數(shù)據(jù),數(shù)據(jù)可重復(fù)。具體形式如圖2所示: 圖2 各集合元素存放示例 (1)Collection:集合層次中的根接口,JDK 沒有提供這個(gè)接口直接的實(shí)現(xiàn)類。 (2)Set:不能包含重復(fù)的元素。 (3) List:是一個(gè)有序的集合,可以包含重復(fù)的元素。提供了按索引訪問(wèn)的方式。 (4)Map:包含了 key-value 對(duì)。Map 不能包含重復(fù)的 key。 三、List用法總結(jié)3.1 List接口List的主要特征使其元素已先行方式存儲(chǔ),集合中允許存放重復(fù)對(duì)象。List接口主要的實(shí)現(xiàn)類包括: (1)ArrayList:代表長(zhǎng)度可變的數(shù)組。允許對(duì)元素進(jìn)行快速的隨機(jī)訪問(wèn),但是向ArrayList中插入與刪除元素的速度較慢。 (2)LinkedList :在實(shí)現(xiàn)中采用鏈表數(shù)據(jù)結(jié)構(gòu),元素之間是雙鏈接。對(duì)順序訪問(wèn)進(jìn)行了優(yōu)化,向List中插入和刪除元素的速度較快,隨機(jī)訪問(wèn)速度則相對(duì)較慢,隨機(jī)訪問(wèn)是指檢索位于特定索引位置元素,當(dāng)需要快速插入和刪除時(shí)LinkedList成為L(zhǎng)ist中的不二選擇。 (3)Vector :是ArrayList的線程安全版本,性能比ArrayList要低,現(xiàn)在已經(jīng)很少使用。 3.2 ArrayList用法3.2.1、ArrayList是個(gè)集合 集合是可以往里面添東西的,用add(E e)方法往里面加(把E都看做Object) 例子:ArrayList類中的add和get方法(add方法向集合中添加數(shù)據(jù),get方法將集合中指定下標(biāo)位置的數(shù)據(jù)取出) (1)size()方法,返回集合中的元素個(gè)數(shù),類似于數(shù)組中的length屬性 (2)clear()方法,將集合中的所有元素都給清除 (3)isEmpty()方法判斷集合是否為空,為空返回true (4)remove(int index)方法是刪除集合中指定位置的元素,清除的原理是你清除了第一個(gè)后,后面的元素往前移,第一個(gè)變第0個(gè)了,原來(lái)第三個(gè)元素就沒啦 (5)remove(Object ob)是remove的重載,一個(gè)是根據(jù)索引來(lái)刪除,一個(gè)是根據(jù)具體對(duì)象來(lái)刪除,比如remove('Hello'); (6)indexOf(Obejct ob)判斷某個(gè)元素在索引的第幾個(gè)位置上。 在數(shù)組中查看數(shù)組元素個(gè)數(shù),用數(shù)組的length屬性,在集合中查看集合元素個(gè)數(shù),用集合的size()方法。 3.2.2、ArrayList使用范例 import java.awt.List;
import java.util.ArrayList;
import java.util.Iterator;
/**
* @author 林炳文
* @time 2015/2/5
* ArrayList用法示例說(shuō)明
*
*/
public class Main {
public static void main(String[] args) {
//ArrayList用法示例
ArrayList<String> m_ArrayList=new ArrayList<String>();
m_ArrayList.add('Evankaka');
m_ArrayList.add('林炳文');
m_ArrayList.add('德德');
m_ArrayList.add('Evankaka');
m_ArrayList.add('小紅');
m_ArrayList.set(2,'文炳林');// 將索引位置為2的對(duì)象修改
m_ArrayList.add(3,'秀秀');// 將對(duì)象添加到索引位置為3的位置
//ArrayList遍歷方法1
Iterator<String> it_ArrayList = m_ArrayList.iterator();
System.out.println('ArrayList遍歷方法1');
while (it_ArrayList.hasNext()) {
System.out.println(it_ArrayList.next());
}
//ArrayList遍歷方法2
System.out.println('ArrayList遍歷方法2');
for(Object o:m_ArrayList){
System.out.println(o);
}
//ArrayList遍歷方法2
System.out.println('ArrayList遍歷方法3');
for(int i = 0; i<m_ArrayList.size(); i ){
System.out.println(m_ArrayList.get(i));
}
//刪除元素
m_ArrayList.remove('Evankaka');
it_ArrayList = m_ArrayList.iterator();
System.out.println('ArrayList刪除元素后的遍歷');
while (it_ArrayList.hasNext()) {
String m_String=it_ArrayList.next();
if(m_String.equals('秀秀')){
it_ArrayList.remove();
}else{
System.out.println(m_String);
}
}
}
} 輸出結(jié)果: ArrayList遍歷方法1 3.2.3、ArrayList注意 (1)使用Iterator迭代集合過(guò)程中,不可修改集合元素,否則會(huì)引發(fā)異常。并且Iterator只能向后迭代 (2)如果你想在循環(huán)過(guò)程中去掉某個(gè)元素,只能調(diào)用it.remove方法, 不能使用list.remove方法, 否則一定出并發(fā)訪問(wèn)的錯(cuò)誤. 3.3 LinkedList用法LinkedList類是鏈表節(jié)點(diǎn)各種操作的實(shí)現(xiàn),LinkedList類實(shí)現(xiàn)了一個(gè)帶有頭尾引用的通用型雙向鏈表。注意,此實(shí)現(xiàn)不是同步的。如果多個(gè)線程同時(shí)訪問(wèn)列表,而其中至少一個(gè)線程從結(jié)構(gòu)上修改了該列表,則它必須保持外部同步。(結(jié)構(gòu)修改指添加或刪除一個(gè)或多個(gè)元素的任何操作;僅設(shè)置元素的值不是結(jié)構(gòu)修改。)這一般通過(guò)對(duì)自然封裝該列表的對(duì)象進(jìn)行同步操作來(lái)完成。如果不存在這樣的對(duì)象,則應(yīng)該使用 Collections.synchronizedList 方法來(lái)“包裝”該列表。最好在創(chuàng)建時(shí)完成這一操作,以防止對(duì)列表進(jìn)行意外的不同步訪問(wèn)。 四、set接口set集合中多個(gè)對(duì)象之間沒有明顯的順序,set與Collection的結(jié)構(gòu)基本上完全一樣,不同在于set不能包含重復(fù)元素。Set判斷兩個(gè)對(duì)象相同不是使用==運(yùn)算符,而是根據(jù)equals方法。也就是說(shuō)主要兩個(gè)對(duì)象用equals方法比較返回true,Set就不會(huì)接受這兩個(gè)對(duì)象。 HashSet是Set接口的典型實(shí)現(xiàn),大多數(shù)時(shí)候使用Set集合就是使用這個(gè)類。 4.1 HashSet說(shuō)明與范例 HashSet按hash算法來(lái)存儲(chǔ)集合中的元素,因此具有很好的存儲(chǔ)和查找性能。 使用范例: package com.collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
public class Main
{
public static void main(String [] args)
{
HashSet h=new HashSet();
h.add('1st');
h.add('2nd');
h.add(new Integer(3));
h.add(new Double(4.0));
h.add('2nd'); //重復(fù)元素,未被添加
h.add(new Integer(3)); //重復(fù)元素,未被添加
h.add(new Date());
System.out.println('開始:size=' h.size());
Iterator it=h.iterator();
while(it.hasNext())
{
Object o=it.next();
System.out.println(o);
}
h.remove('2nd');
System.out.println('移除元素后:size=' h.size());
System.out.println(h);
}
} 結(jié)果:開始:size=5 4.2 TreeSet TreeSet描述的是Set的一種變體——可以實(shí)現(xiàn)排序等功能的集合,它在將對(duì)象元素添加到集合中時(shí)會(huì)自動(dòng)按照某種比較規(guī)則將其插入到有序的對(duì)象序列中,并保證該集合元素組成時(shí)刻按照“升序”排列。 使用范例: package com.collection;
import java.util.TreeSet;
import java.util.Iterator;
public class Main
{
public static void main(String [] args)
{
TreeSet ts=new TreeSet();
ts.add('orange');
ts.add('apple');
ts.add('banana');
ts.add('grape');
Iterator it=ts.iterator();
while(it.hasNext())
{
String fruit=(String)it.next();
System.out.println(fruit);
}
}
} 結(jié)果: apple 4.3 Set總結(jié)(1) HashSet和TreeSet是Set的兩個(gè)典型實(shí)現(xiàn)。HashSet的性能總是比TreeSet好(特別是常用的添加、查詢等操作),因?yàn)門reeSet需要額外的紅黑樹算法來(lái)維護(hù)集合元素的次序。只有當(dāng)需要一個(gè)保存排序的Set時(shí),才應(yīng)該使用TreeSet,否則都應(yīng)該使用HashSet。(2) LinkedHashSet是HashSet的子類,該集合也是根據(jù)元素hashCode值來(lái)決定元素存儲(chǔ)位置,但它同時(shí)使用鏈表維護(hù)元素的次序,這樣使得元素看起來(lái)是以插入的順序保存的。LinkedHashSet需要維護(hù)元素的插入順序,因此性能略低于HashSet的性能,但在迭代訪問(wèn)Set里的全部元素時(shí)將有很好的性能,又因?yàn)殒湵淼拇嬖?,遍歷LinkedHashSet會(huì)更快。 (3)TreeSet是SortedSet接口的實(shí)現(xiàn),TreeSet可以確保集合元素處于排序狀態(tài),TreeSet并不是根據(jù)元素的插入順序進(jìn)行排序,而是根據(jù)元素的實(shí)際值來(lái)進(jìn)行排序的。 (4)EnumSet是所有Set實(shí)現(xiàn)類中性能最好的,但它只能保存同一個(gè)枚舉類的枚舉值作為集合元素。 (5)必須指出的是Set的三個(gè)實(shí)現(xiàn)類HashSet、TreeSet和EnumSet都是線程不安全的,如果有多條線程同時(shí)訪問(wèn)一個(gè)Set集合,并有超過(guò)一條線程修改了該Set集合,則必須手動(dòng)保證該Set集合的同步性。通??梢酝ㄟ^(guò)Collections工具類的synchronizedSortedSet方法來(lái)包裝該Set集合。此操作最好在創(chuàng)建時(shí)進(jìn)行。 五 Map接口 將鍵映射到值的對(duì)象。一個(gè)映射不能包含重復(fù)的鍵;每個(gè)鍵最多只能映射到一個(gè)值。此接口取代 Dictionary 類,后者完全是一個(gè)抽象類,而不是一個(gè)接口。
Map 提供了一個(gè)更通用的元素存儲(chǔ)方法。Map 集合類用于存儲(chǔ)元素對(duì)(稱作“鍵”和“值”),其中每個(gè)鍵映射到一個(gè)值。從概念上而言,您可以將 List 看作是具有數(shù)值鍵的 Map。而實(shí)際上,除了 List 和 Map 都在定義 java.util 中外,兩者并沒有直接的聯(lián)系。本文將著重介紹核心 Java 發(fā)行套件中附帶的 Map,同時(shí)還將介紹如何采用或?qū)崿F(xiàn)更適用于您應(yīng)用程序特定數(shù)據(jù)的專用 Map。 5.1、了解 Map 接口和方法 Java 核心類中有很多預(yù)定義的 Map 類。在介紹具體實(shí)現(xiàn)之前,我們先介紹一下 Map 接口本身,以便了解所有實(shí)現(xiàn)的共同點(diǎn)。Map 接口定義了四種類型的方法,每個(gè) Map 都包含這些方法。下面,我們從兩個(gè)普通的方法開始對(duì)這些方法加以介紹。 表 1:覆蓋的方法。我們將這 Object 的這兩個(gè)方法覆蓋,以正確比較 Map 對(duì)象的等價(jià)性。
5.2、Map 構(gòu)建 Map 定義了幾個(gè)用于插入和刪除元素的變換方法。 表 2:Map 更新方法: 可以更改 Map 內(nèi)容。
盡管您可能注意到,縱然假設(shè)忽略構(gòu)建一個(gè)需要傳遞給 putAll() 的 Map 的開銷,使用 putAll() 通常也并不比使用大量的 put() 調(diào)用更有效率,但 putAll() 的存在一點(diǎn)也不稀奇。這是因?yàn)?,putAll() 除了迭代 put() 所執(zhí)行的將每個(gè)鍵值對(duì)添加到 Map 的算法以外,還需要迭代所傳遞的 Map 的元素。但應(yīng)注意,putAll() 在添加所有元素之前可以正確調(diào)整 Map 的大小,因此如果您未親自調(diào)整 Map 的大?。ㄎ覀儗?duì)此進(jìn)行簡(jiǎn)單介紹),則 putAll() 可能比預(yù)期的更有效。 5.3、查看 Map 迭代 Map 中的元素不存在直接了當(dāng)?shù)姆椒?。如果要查詢某個(gè) Map 以了解其哪些元素滿足特定查詢,或如果要迭代其所有元素(無(wú)論原因如何),則您首先需要獲取該 Map 的“視圖”。有三種可能的視圖。
前兩個(gè)視圖均返回 Set 對(duì)象,第三個(gè)視圖返回 Collection 對(duì)象。就這兩種情況而言,問(wèn)題到這里并沒有結(jié)束,這是因?yàn)槟鸁o(wú)法直接迭代 Collection 對(duì)象或 Set 對(duì)象。要進(jìn)行迭代,您必須獲得一個(gè) Iterator 對(duì)象。因此,要迭代 Map 的元素,必須進(jìn)行比較煩瑣的編碼
Iterator keyValuePairs = aMap.entrySet().iterator();
Iterator keys = aMap.keySet().iterator();
Iterator values = aMap.values().iterator();
值得注意的是,這些對(duì)象(Set、Collection 和 Iterator)實(shí)際上是基礎(chǔ) Map 的視圖,而不是包含所有元素的副本。這使它們的使用效率很高。另一方面,Collection 或 Set 對(duì)象的 toArray() 方法卻創(chuàng)建包含 Map 所有元素的數(shù)組對(duì)象,因此除了確實(shí)需要使用數(shù)組中元素的情形外,其效率并不高。 5.4、遍歷mappackage com.test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put('first', 'linlin');
map.put('second', 'bingbing');
map.put('third', 'wenwen');
map.put('first', 'linlin2');
// 第一種:通過(guò)Map.keySet遍歷key和value
System.out.println('===================通過(guò)Map.keySet遍歷key和value:===================');
for (String key : map.keySet()) {
System.out.println('key= ' key ' and value= ' map.get(key));
}
// 第二種:通過(guò)Map.entrySet使用iterator遍歷key和value
System.out.println('===================通過(guò)Map.entrySet使用iterator遍歷key和value:===================');
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println('key= ' entry.getKey() ' and value= '
entry.getValue());
}
// 第三種:通過(guò)Map.entrySet遍歷key和value
System.out.println('===================通過(guò)Map.entrySet遍歷key和value:===================');
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println('key= ' entry.getKey() ' and value= '
entry.getValue());
}
// 第四種:通過(guò)Map.values()遍歷所有的value,但是不能遍歷鍵key
System.out.println('===================通過(guò)Map.values()遍歷所有的value:===================');
for (String v : map.values()) {
System.out.println('value= ' v);
}
}
}
輸出結(jié)果如下 |
|
來(lái)自: Levy_X > 《JAVAWEB學(xué)習(xí)資料》