## Java編程那些事兒80——集合框架簡述
陳躍峰
出自:[http://blog.csdn.net/mailbomb](http://blog.csdn.net/mailbomb)
### 9.6.3 集合框架簡述
在JDK API中專門設計了一組類,這組類的功能就是實現各種各樣方式的數據存儲,這樣一組專門用來存儲其它對象的類,一般被稱為對象容器類,簡稱容器類,這組類和接口的設計結構也被統稱為集合框架(Collection Framework)。
這組類和接口都包含在java.util包中。
為了使整個集合框架中的類便于使用,在設計集合框架時大量的使用接口,實際實現的功能類實現對應的接口,這樣可以保證各個集合類的使用方式保持統一。
在集合框架中,提供的存儲方式共有兩種:
1、按照索引值操作數據
在這種存儲方式中,為每個存儲的數據設定一個索引值,存儲在容器中的第一個元素索引值是0,第二個索引值是1,依次類推。在操作數據時按照索引值操作對應的數據,實現這種方式的集合類都實現java.util.Collection接口。
2、按照名稱操作數據
在這種存儲方式中,為每個存儲的數據設定一個名稱(任意非null的對象都可以作為名稱),以后按照該名稱操作該數據,要求名稱不能重復,每個名稱對應唯一的一個值。這種存儲數據的方式也稱作名稱-數值對,也就是名值對存儲。實現這種方式的幾個類都實現java.util.Map接口。
這里“按照索引值操作數據”的存儲方式,又按照容器內部是否能夠存儲重復的元素,劃分成兩類:
1、允許存儲重復元素。
這種存儲方式中,所有的類都實現了java.util.List接口。
2、不允許存儲重復元素。
這種存儲方式中,所有的類都實現了java.util.Set接口。
這樣,集合框架中的類就分成了三大類:
1、List系列
該系列中的類按照索引值來操作數據,允許存放重復的元素。
2、Set系列
該系列中的類按照索引值來操作數據,不允許存放重復的元素。
3、Map系列
該系列中的類按照名稱來操作數據,名稱不允許重復,值可以重復,一個名稱對應一個唯一的值。
而在數據結構中,實現數據的存儲又可以使用不同的數據結構類型進行存儲,例如數組、鏈表、棧、隊列和樹等,則以上三類集合框架可以使用不同的數據結構類進行實現,使用每種數據結構則具備該中數據結構的特點。例如使用數組則訪問速度快,使用鏈表則便于動態插入和刪除等,這樣就造成了集合框架的復雜性。
另外,在將對象存儲到集合類中,為了加快存儲的速度,要求被存儲對象的類中必須覆蓋equals方法和hashCode方法。
對于這些集合類,下面按照以上三個系列的順序一一進行說明。
#### 9.6.3.1 List系列
List系列的類均實現List接口,大部分的類都以List作為類名的后綴,也有部分該體系中的類命名比較特殊。
該系列中的類,比較常見的有ArrayList和LinkedList兩個。其中ArrayList是以數組為基礎實現的List,而LinkedList則是以鏈表為基礎實現的List,ArrayList擁有數組的優點,而LinkedList擁有鏈表的優點。
由于該體系中的類均實現List接口,所以在這些類的內部,相同的功能方法聲明是保持一致的,下面進行一一介紹:
a、add方法
boolean add(Object o)
該方法的作用是追加對象o到已有容器的末尾。
另外一個add方法:
void add(int index, Object element)
該方法的作用是將對象element插入到容器中索引值為index的位置,原來位于該位置的對象以及后續的內容將依次向后移動。
b、addAll方法
boolean addAll(Collection c)
該方法的作用是將容器對象c中的每個元素依次添加到當前容器的末尾。
另外一個addAll方法:
boolean addAll(int index, Collection c)
該方法的作用是將容器對象c中的第一個元素插入到當前容器中索引值為index的位置,第二個元素插入到當前容器中索引值為index+1的位置,依次類推。而當前容器中原來位于index以及index索引值以后的元素則依次向后移動。
c、get方法
Object get(int index)
該方法的作用是返回當前容器對象中索引值為index的元素的內容。
d、indexOf方法
int indexOf(Object o)
該方法的作用是查找當前容器中是否存在對象o,如果存在則返回該對象第一次出現位置的索引值,如果不存在則返回-1。
另外一個方法lastIndexOf則是從末尾向前查找,返回從末尾向前第一次出現位置的索引值,如果不存在則返回-1。
e、remove方法
Object remove(int index)
該方法的作用是刪除索引值為index的對象的內容,如果刪除成功則返回被刪除對象的內容。
另外一個remove方法:
boolean remove(Object o)
該方法的作用是刪除對象內容為o的元素,如果相同的對象有多個,則只刪除索引值小的對象。如果刪除成功則返回true,否則返回false。
無論使用哪一個remove方法,類內部都自動移動將被刪除位置后續的所有元素向前移動,保證索引值的連續性。
f、set方法
Object set(int index, Object element)
該方法的作用是修改索引值為index的內容,將原來的內容修改成對象element的內容。
g、size方法
int size()
該方法的作用是返回當前容器中已經存儲的有效元素的個數。
h、toArray方法
Object[] toArray()
該方法的作用是將當前容器中的元素按照順序轉換成一個Object數組。
下面是一個簡單的以ArrayList類為基礎實現的List系列中類基本使用的示例,代碼如下:
~~~
?????????????????? import java.util.*;
/**
?* 以ArrayList類為基礎演示List系列類的基本使用
?*/
public class ArrayListUse {
???????? public static void main(String[] args) {
?????????????????? //容器對象的初始化
?????????????????? List list = new ArrayList();?????????????????
?????????????????? //添加數據
?????????????????? list.add("1");
?????????????????? list.add("2");
?????????????????? list.add("3");
?????????????????? list.add("1");
?????????????????? list.add("1");????????????
?????????????????? //插入數據
?????????????????? list.add(1,"12");???????????????
?????????????????? //修改數據
?????????????????? list.set(2, "a");??????????????????
?????????????????? //刪除數據
?????????????????? list.remove("1");??????????????
?????????????????? //遍歷
?????????????????? int size = list.size();? //獲得有效個數
?????????????????? //循環有效索引值
?????????????????? for(int i = 0;i < size;i++){
??????????????????????????? System.out.println((String)list.get(i));
?????????????????? }
???????? }
}
~~~
該程序的運行結果為:
12
a
3
1
1
在List系列中,還包含了Stack(棧)類和Vector(向量)類,Stack類除了實現List系列的功能以外,還實現了棧的結構,主要實現了出棧的pop方法和入棧的push方法。
而Vector類由于需要兼容老版本JDK中緣故,所以在實現的方法中需要提供老版本Vector類中對應的方法,這樣導致Vector類中相同或類似的功能方法一般是成對出現的。
#### 9.6.3.2 Set系列
Set系列中的類都實現了Set接口,該系列中的類均以Set作為類名的后綴。該系列中的容器類,不允許存儲重復的元素。也就是當容器中已經存儲一個相同的元素時,無法實現添加一個完全相同的元素,也無法將已有的元素修改成和其它元素相同。
Set系列中類的這些特點,使得在某些特殊場合的使用比較適合。
該系列中常見的類有:
1、CopyOnWriteArraySet
以數組為基礎實現的Set類。
2、HashSet
以哈希表為基礎實現的Set類。
3、LinkedHashSet
以鏈表為基礎實現的Set類。
4、TreeSet
以樹為基礎實現的Set類。
以不同的數據結構類型實現的Set類,擁有不同數據結構帶來的特性,在實際使用時,根據邏輯的需要選擇合適的Set類進行使用。
Set系列中的類的方法和List系列中的類的方法要比List系列中少很多,例如不支持插入和修改,而且對于Set系列中元素的遍歷也需要轉換為專門的Iterator(迭代器)對象才可以進行遍歷,遍歷時順序和Set中存儲的順序會有所不同。
下面是以HashSet類為基礎實現的示例代碼,代碼如下:
~~~
import java.util.*;
/**
?* 以HashSet為基礎演示Set系列類的基本使用
?*/
public class HashSetUse {
???????? public static void main(String[] args) {
?????????????????? //容器對象的初始化
?????????????????? Set set = new HashSet();?????????
?????????????????? //添加元素
?????????????????? set.add("1");
?????????????????? set.add("2");
?????????????????? set.add("3");
?????????????????? set.add("1");
?????????????????? set.add("1");??????????????????????????????
?????????????????? //刪除數據
?????????????????? //set.remove("1");??????????
?????????????????? //遍歷
?????????????????? Iterator iterator = set.iterator();
?????????????????? while(iterator.hasNext()){
??????????????????????????? System.out.println((String)iterator.next());
?????????????????? }
???????? }
}
~~~
該程序的運行結果為:
3
2
1
#### 9.6.3.3 Map系列
Map系列中的類都實現了Map接口,該系列中的部分類以Map作為類名的后綴。該系列容器類存儲元素的方式和以上兩種完全不同。
Map提供了一種使用“名稱:值”這樣的名稱和數值對存儲數據的方法,在該存儲方式中,名稱不可以重復,而不同的名稱中可以存儲相同的數值。具體這種存儲的格式將在示例代碼中進行實現。
在這種存儲結構中,任何不為null的對象都可以作為一個名稱(key)來作為存儲的值(value)的標識,使用這種形式更利于存儲比較零散的數據,也方便數據的查找和獲得。Map類中存儲的數據沒有索引值,系統會以一定的形式索引存儲的名稱,從而提高讀取數據時的速度。
該系列中常見的類有:
1、HashMap
以Hash(哈希表)為基礎實現的Map類。
2、LinkedHashMap
以鏈表和Hash(哈希表)為基礎實現的Map類。
3、TreeMap
以樹為基礎實現的Map類。
和上面的結構類似,以不同的數據結構實現的Map類,擁有不同數據結構的特點,在實際的項目中使用時,根據需要選擇合適的即可。
該系列的類中常見的方法如下:
a、get方法
Object get(Object key)
該方法的作用是獲得當前容器中名稱為key的結構對應的值。
b、keySet方法
Set keySet()
該方法的作用是返回當前容器中所有的名稱,將所有的名稱以Set的形式返回。使用這個方法可以實現對于Map中所有元素的遍歷。
c、put方法
Object put(Object key, Object value)
該方法的作用是將值value以名稱key的形式存儲到容器中。
d、putAll方法
void putAll(Map t)
該方法的作用是將Map對象t中的所有數據按照原來的格式存儲到當前容器類中,相當于合并兩個Map容器對象。
e、remove方法
Object remove(Object key)
該方法的作用是刪除容器中名稱為key的值。
f、size方法
int size()
該方法的作用是返回當前日期中存儲的名稱:值數據的組數。
g、values方法
Collection values()
該方法的作用是返回當前容器所有的值組成的集合,以Collection對象的形式返回。
下面是一個簡單的示例,在該示例中演示Map系列類的基本使用,代碼如下:
~~~
import java.util.*;
/**
?* 以HashMap為基礎演示Map系列中類的使用
?*/
public class HashMapUse {
???????? public static void main(String[] args) {
?????????????????? //容器對象的初始化
?????????????????? Map map = new HashMap();???????????
?????????????????? //存儲數據
?????????????????? map.put("蘋果", "2.5");
?????????????????? map.put("桔子", "2.5");
?????????????????? map.put("香蕉", "3");
?????????????????? map.put("菠蘿", "2");?????????????
?????????????????? //刪除元素
?????????????????? map.remove("桔子");??????????????
?????????????????? //修改元素的值
?????????????????? map.put("菠蘿", "5");?????????????
?????????????????? //獲得元素個數
?????????????????? int size = map.size();
?????????????????? System.out.println("個數是:" + size);??????????
?????????????????? //遍歷Map
?????????????????? Set set = map.keySet();
?????????????????? Iterator iterator = set.iterator();
?????????????????? while(iterator.hasNext()){
??????????????????????????? //獲得名稱
??????????????????????????? String name = (String)iterator.next();
??????????????????????????? //獲得數值
??????????????????????????? String value = (String)map.get(name);
??????????????????????????? //顯示到控制臺
??????????????????????????? System.out.println(name + ":" + value);
?????????????????? }
???????? }
}
~~~
該程序的運行結果為:
個數是:3
香蕉:3
菠蘿:5
蘋果:2.5
#### 9.6.3.4 使用示例
如前所述,集合框架中的類只是提供了一種數據存儲的方式,在實際使用時,可以根據邏輯的需要選擇合適的集合類進行使用。
下面以一個字符串計算的示例演示集合類的實際使用。
該程序的功能為計算一個數字字符串,例如”1+2*31-5”、”12*30/34-450”等,的計算結果,在該示例中支持四則運算,但是不支持括號。本示例中計算的字符串要求合法。
該程序實現的原理是:首先按照運算符作為間隔,將字符串差分為數字字符串和運算符字符串的序列,由于分拆出的字符串數量不固定,所以存儲到List系列的Vector容器中,然后按照運算符的優先級進行計算。
該程序的代碼如下:
~~~
import java.util.*;
/**
?* 計算字符串的值
?*/
public class CalcStr {
???????? public static void main(String[] args) {
?????????????????? String s = "1+20*3/5";
?????????????????? double d = calc(s);
?????????????????? System.out.println(d);
???????? }???????
???????? /**
???????? ?* 計算字符串的值
???????? ?* @param s 需要計算的字符串
???????? ?* @return 計算結果
???????? ?*/
???????? public static double calc(String s){
?????????????????? //拆分字符串
?????????????????? Vector v = split(s);
?????????????????? //print(v); //測試代碼
?????????????????? //計算字符串
?????????????????? double d = calcVector(v);
?????????????????? return d;
???????? }
????????
???????? /**
???????? ?* 將字符串拆分為數字和運算符。
???????? ?* 例如:"1+23*4"則拆分為:"1"、"+"、"23"、"*"和"4"
???????? ?* @param s 需要拆分的字符串
???????? ?* @return 拆分以后的結果
???????? ?*/
???????? private static Vector split(String s){
?????????????????? Vector v = new Vector();
?????????????????? String content = "";
?????????????????? int len = s.length(); //字符串長度
?????????????????? char c;
?????????????????? for(int i = 0;i < len;i++){
??????????????????????????? c = s.charAt(i);
??????????????????????????? //判斷是否為運算符
??????????????????????????? if(c == '+' ||
???????????????????????????????????? c == '-' ||
???????????????????????????????????? ?c == '*' ||
???????????????????????????????????? ? c == '/'){
???????????????????????????????????? //存儲數字
???????????????????????????????????? v.add(content);
???????????????????????????????????? //存儲運算符
???????????????????????????????????? v.add("" + c);
???????????????????????????????????? //清除已有字符串
???????????????????????????????????? content = "";
??????????????????????????? }else{
???????????????????????????????????? content += c; //連接字符串
??????????????????????????? }
?????????????????? }
?????????????????? v.add(content); //添加最后一個數字
?????????????????? return v;
???????? }
????????
???????? /**
???????? ?* 測試代碼,輸出拆分以后的結果
???????? ?* @param v 需要打印的Vector對象
???????? ?*/
???????? private static void print(Vector v){
?????????????????? int size = v.size();
?????????????????? for(int i = 0;i < size;i++){
??????????????????????????? System.out.println((String)v.get(i));
?????????????????? }
???????? }
????????
???????? /**
???????? ?* 計算Vector中的數據
???????? ?* @param v 存儲拆分后字符串的Vector
???????? ?* @return 計算結果
???????? ?*/
???????? private static double calcVector(Vector v){
?????????????????? int index1;
?????????????????? int index2;
?????????????????? //計算乘除
?????????????????? while(true){
??????????????????????????? index1 = v.indexOf("*"); //乘號索引值
??????????????????????????? index2 = v.indexOf("/"); //除號索引值
??????????????????????????? //無乘除符號
??????????????????????????? if(index1 == - 1 && index2 == -1){
???????????????????????????????????? break;? //結束循環
??????????????????????????? }??????????????????????????
??????????????????????????? //如果有乘號
??????????????????????????? if(index1 != -1){
???????????????????????????????????? //沒有除號或乘號在前
???????????????????????????????????? if(index2 == -1 || index1 < index2){
?????????????????????????????????????????????? String s1 = (String)v.get(index1 - 1); //第一個數字
?????????????????????????????????????????????? String opr = (String)v.get(index1); //運算符
?????????????????????????????????????????????? String s2 = (String)v.get(index1 + 1); //第二個數字
?????????????????????????????????????????????? //計算
?????????????????????????????????????????????? String answer = calc(s1,s2,opr);
?????????????????????????????????????????????? //計算以后的處理
?????????????????????????????????????????????? handle(answer,index1 - 1,v);
???????????????????????????????????? }
??????????????????????????? }
??????????????????????????? //有除號
??????????????????????????? if(index2 != -1){
???????????????????????????????????? //沒有乘號或除號在前
???????????????????????????????????? if(index1 == -1 || index2 < index1){
?????????????????????????????????????????????? String s1 = (String)v.get(index2 - 1); //第一個數字
?????????????????????????????????????????????? String opr = (String)v.get(index2); //運算符
?????????????????????????????????????????????? String s2 = (String)v.get(index2 + 1); //第二個數字
?????????????????????????????????????????????? //計算
?????????????????????????????????????????????? String answer = calc(s1,s2,opr);
?????????????????????????????????????????????? //計算以后的處理
?????????????????????????????????????????????? handle(answer,index2 - 1,v);
???????????????????????????????????? }
??????????????????????????? }
?????????????????? }
?????????????????? //計算加
?????????????????? int index3 = v.indexOf("+");
?????????????????? while(index3 != -1){ //有加號
??????????????????????????? String s1 = (String)v.get(index3 - 1); //第一個數字
??????????????????????????? String opr = (String)v.get(index3); //運算符
??????????????????????????? String s2 = (String)v.get(index3 + 1); //第二個數字
??????????????????????????? //計算
??????????????????????????? String answer = calc(s1,s2,opr);
??????????????????????????? //計算以后的處理
??????????????????????????? handle(answer,index3 - 1,v);
??????????????????????????? //獲得下一個加號的位置
??????????????????????????? index3 = v.indexOf("+");
?????????????????? }
??????????????????
?????????????????? //計算減
?????????????????? index3 = v.indexOf("-");
?????????????????? while(index3 != -1){ //有加號
??????????????????????????? String s1 = (String)v.get(index3 - 1); //第一個數字
??????????????????????????? String opr = (String)v.get(index3); //運算符
??????????????????????????? String s2 = (String)v.get(index3 + 1); //第二個數字
??????????????????????????? //計算
??????????????????????????? String answer = calc(s1,s2,opr);
??????????????????????????? //計算以后的處理
??????????????????????????? handle(answer,index3 - 1,v);
??????????????????????????? //獲得下一個減號的位置
??????????????????????????? index3 = v.indexOf("-");
?????????????????? }
?????????????????? //反饋結果
?????????????????? String data = (String)v.get(0);
?????????????????? return Double.parseDouble(data);
???????? }
????????
???????? /**
???????? ?* 計算兩個字符串類型的值運算結果
???????? ?* @param number1 數字1
???????? ?* @param number2 數字2
???????? ?* @param opr 運算符
???????? ?* @return 運算結果
???????? ?*/
???????? private static String calc(String number1,String number2,String opr){
?????????????????? //將字符串轉換為數字
?????????????????? double d1 = Double.parseDouble(number1);
?????????????????? double d2 = Double.parseDouble(number2);
?????????????????? //判斷運算符
?????????????????? if(opr.equals("+")){
??????????????????????????? return "" + (d1 + d2);
?????????????????? }
?????????????????? if(opr.equals("-")){
??????????????????????????? return "" + (d1 - d2);
?????????????????? }
?????????????????? if(opr.equals("*")){
??????????????????????????? return "" + (d1 * d2);
?????????????????? }
?????????????????? if(opr.equals("/")){
??????????????????????????? return "" + (d1 / d2);
?????????????????? }
?????????????????? return "0";? //運算符錯誤時返回0
???????? }
????????
???????? /**
???????? ?* 計算以后的處理
???????? ?* @param answer 計算結果
???????? ?* @param index 參與計算的三個字符串中第一個字符串的起始位置
???????? ?* @param v 存儲字符串的容器
???????? ?*/
???????? private static void handle(String answer,int index,Vector v){
?????????????????? //刪除計算過的字符串
?????????????????? for(int i = 0;i < 3;i++){
??????????????????????????? v.remove(index);
?????????????????? }
?????????????????? //將計算結果插入到index位置
?????????????????? v.insertElementAt(answer, index);
???????? }
}
~~~
該程序的運行結果為:
13.0
### 9.7 總結
在本章中,主要介紹了java.lang包和java.util包中比較常見的類的使用,熟悉了JDK API的基本使用,掌握了文檔的查閱以及方法調用等一些基本的技能,為后續章節的學習打下堅實的基礎。
- 前言
- (1)序言
- (2)程序設計是什么?
- (3)你適合學習程序設計嗎?
- (4)如何學好程序設計?
- (5)程序設計介紹小結
- (6)計算機軟件基本概念
- (7)進制的概念
- (8)計算機內部的數據表達
- (9)網絡編程基礎
- (10)Java語言簡介
- (11)JDK的獲得、安裝和配置
- (12)第一個HelloWorld程序
- (13)Eclipse基本使用
- (14)Eclipse基礎使用進階
- (15)如何學好Java語法
- (16)代碼框架、關鍵字和標識符
- (17)基本數據類型
- (18)變量和常量
- (19)數據類型轉換
- (20)空白、語句結束和注釋
- (21)算術運算符
- (22)比較運算符
- (23)邏輯運算符
- (24)賦值運算符
- (25)位運算符
- (26)移位運算符
- (27)其它運算符
- (28)運算符優先級
- (29)表達式
- (30)流程控制基礎
- (31)if語句語法(1)
- (32)if語句語法(2)
- (33)if語句語法(3)
- (34)switch語句語法
- (35)while語句語法
- (36)do-while語句語法
- (37)for語句語法
- (38)break和continue語句
- (39)流程控制綜合示例1
- (40)流程控制綜合示例2
- (41)流程控制綜合示例3
- (42)流程控制綜合練習
- (43)數組概述
- (44)數組基礎語法
- (45)數組使用示例1
- (46)數組使用示例2
- (47)數組使用示例3
- (48)多維數組基礎
- (49)多維數組使用示例1
- (50)多維數組使用示例2
- (51)多維數組練習
- (52)方法聲明
- (53)方法聲明示例
- (54)方法調用
- (55)方法重載和參數傳遞
- (56)方法練習
- (57)面向對象基礎
- (58)類(一)
- (59)類(二)
- (60)對象
- (61)面向對象設計方法和面向對象特性(一)
- (62)繼承(二)
- (63)多態性
- (64)訪問控制符、修飾符和其它關鍵字
- (65)static修飾符
- (66)final修飾符
- (67)this和super
- (68)抽象類和接口(一)
- (69)抽象類和接口(二)
- (70)抽象類和接口(三)
- (71)內部類簡介
- (72)包的概念
- (73)JDK文檔使用
- (74)java.lang包介紹1
- (75)String類使用
- (76)StringBuffer類和System類
- (77)包裝類
- (78)時間和日期處理
- (79)Random隨機處理
- (80)集合框架簡述
- (81)異常處理概述
- (82)異常處理語法1
- (83)異常處理語法2
- (84)IO簡介
- (85)IO類體系
- (86)文件操作之File類使用
- (87)文件操作之讀取文件
- (88)文件操作之寫文件
- (89)讀取控制臺輸入
- (90)裝飾流使用1
- (91)裝飾流使用2
- (92)IO使用注意問題
- (93)多線程基礎
- (94)多線程實現方式1
- (95)多線程實現方式2
- (96)多線程使用示例1
- (97)多線程使用示例2
- (98)多線程問題及處理1
- (99)多線程問題及處理2
- (100)多線程問題及處理3
- (101)網絡編程概述
- (102)網絡編程技術1
- (103)網絡編程技術2
- (104)網絡編程技術3
- (105)網絡編程技術4
- (106)網絡編程技術5
- (107)網絡協議概念
- (108)網絡編程示例1
- (109)網絡編程示例2
- (110)網絡編程小結