全部章節 >>>>
本章目錄
7.1 集合概述7
7.1.1 Java集合體系概述
爲了使程序方便地存儲和操縱數目不固定的一組數據,JDK類庫中提供了Java集合,所有Java集合類都位於java.util包中。與Java數組不同,Java集合不能存放基本數據類型,而只能存放對象。
Java集合類主要由兩個接口派生而出,即Collection和Map接口。Collection和Map是Java集合框架的最上層的父接口,這兩個接口又包含其他的子接口和實現類。
Java集合主要包括三種類型: Set(集),List(列表),Map(映射)。
Collection集合體系的繼承樹
實線表示繼承關係,虛線表示實現關係
Map體系的繼承樹
Java集合的三種數據類型存儲示意圖
1、Set特點
類似於一個罐子,將一個對象添加到Set集合時,Set集合無法記住添加此元素的順序
Set集合中的元素是不能重複的,否則系統無法準確識別此元素。
2、List特點
類似於一個數組,它可以記錄每個元素添加的順序,但List長度可變。
3、Map特點
Map集合的存放方式,同樣類似於一個罐子,但Map集合中的每項數據都由兩個值組成。它們分別爲key和value,key不可以重複,但是value可以重複。
Collection接口常用方法
方法名 |
說明 |
boolean add(Object obj) |
向集合中添加一個元素 |
boolean addAll(Collection c) |
將集合c的所有元素添加到指定集合中 |
void clear() |
清除集合中的所有元素,此時集合長度變爲0 |
boolean contains(Object obj) |
返回集合中是否包含指定的元素 |
boolean contains(Collection c) |
返回集合中是否包含指定的c集合 |
Boolean isEmpty() |
判斷集合是否爲空。集合長度爲0時返回true,否則返回false |
Iterator iterator() |
返回一個Iterator對象,用於遍歷集合中的元素 |
boolean remove(Object obj) |
刪除集合中的指定元素obj,當集合中包含一個或多個元素obj時,僅刪除第一個符合條件的元素 |
int size() |
返回集合中元素的個數 |
Object[] toArray() |
將當前集合轉換成一個Object[]類型的數組 |
7.1.2 實踐練習
7.2 List集合
List集合代表一個元素是有序的、且可以重複的、可以爲null的集合。
集合中每個元素都有其對應的順序索引,List集合允許添加重複元素,可以通過索引來訪問指定位置的集合元素。
List 的數據結構就是一個序列,存儲內容時直接在內存中開闢一塊連續的空間,然後將空間地址與索引對應。
List最常見的實現類是ArrayList和LinkedList。
除Collection接口的所有方法之外List還擁有的其他方法
方法名 |
說明 |
void add(int index, Object element) |
添加對象element到位置index上 |
boolean addAll(int index, Collection collection) |
在index位置後添加容器collection中所有的元素 |
Object get(int index) |
取出下標爲index的位置的元素 |
int indexOf(Object element) |
查找對象element在List中第一次出現的位置 |
int lastIndexOf(Object element) |
查找對象element在List中最後出現的位置 |
Object remove(int index) |
刪除index位置上的元素,並返回被刪除的這個元素 |
Object set(int index,Object element) |
將index位置上的所示對象替換爲element並返回被替換 |
7.2.1 ArrayList實現類
ArrayList是基於數組實現的List類,ArrayList底層是通過一個長度可變的數組實現的。
ArrayList允許對元素進行快速的隨機訪問,但是向ArrayList中插入與刪除元素的速度較慢。
示例: 演示ArrayList類使用方法
//創建ArrayList對象
ArrayList arrayList=new ArrayList();
arrayList.add("JAVA-DEMO");//向集合中添加字符串對象
arrayList.add(new Hero());//向集合中添加用戶自定義對象
System.out.println("arrayList集合的大小="+arrayList.size());
for(int i=0;i<arrayList.size();i++) //遍歷集合元素
Object obj=arrayList.get(i); //按照下標獲取元素
boolean flag=arrayList.contains("JAVA-DEMO"); //是否包含字符串"JAVA-DEMO"
Object obj=arrayList.remove("JAVA-DEMO");//刪除指定元素字符串"JAVA-DEMO"
System.out.println("被刪除的元素="+obj);
arrayList.set(0, "ANDROID");//將集合下標爲0的元素修改爲ANDORID
7.2.2 LinkedList實現類
LinkedList類在實現時,採用鏈表數據結構,所以向LinkedList中插入和刪除元素的速度較快,隨機訪問速度則相對較慢(隨機訪問是獲取指定下標位置的元素)
LinkedList單獨具有addFirst()、addLast()、getFirst()、getLast()、removeFirst()和removeLast()方法。這些方法使LinkedList可以作爲堆棧、隊列和雙向隊列來使用。
LinkedList常用方法
方法名 |
說明 |
void addFirst(Object o) |
將指定元素o插入列表起始位置 |
addLast(Object o) |
將指定元素o添加至列表末尾處 |
Object removeFirst() |
移除並返回列表的首元素 |
Object removeLast() |
移除並返回列表的首末元素 |
示例:演示LinkedList類使用方法
LinkedList linkedList=new LinkedList();
ArrayList ayList=new ArrayList();
ayList.add("JAVA-DEMO");
ayList.add('中');
//將ayList對象添加至linkedList集合中
linkedList.add(ayList);
//添加自定義類型對象
linkedList.add(new Hero());
linkedList.addFirst(99.8);//向集合頭部添加一個元素
Object obj=linkedList.removeFirst();//刪除頭部元素
示例:比較ArrayList與LinkedList刪除元素的效率
ArrayList aList=new ArrayList(); //創建ArrayList集合
System.out.println("==========ArrayList==========");
long bTime=System.currentTimeMillis(); //獲取當前系統的時間(毫秒數表示)
System.out.println("起始時間:"+bTime);
for(int i=0;i<100000;i++)
aList.add("DEMO"+i);//向集合中添加數據
int size=aList.size();
for(int i=0;i<size;i++)
aList.remove(0);//每次都刪除集合中的第一個元素
long eTime=System.currentTimeMillis();
System.out.println("結束時間:"+eTime);
System.out.println("ArrayList添加、刪除所用時間="+(eTime-bTime)+"毫秒");
//創建LinkedList集合
LinkedList lList=new LinkedList();
...
System.out.println("LinkedList添加、刪除所用時間="+(edTime-bginTime)+"毫秒");
示例:比較ArrayList與LinkedList訪問元素的效率
ArrayList aList=new ArrayList(); //創建ArrayList集合
System.out.println("==========ArrayList==========");
for(int i=0;i<100000;i++)
aList.add("DEMO"+i);//向集合中添加數據
//獲取當前系統的時間(毫秒數表示)
long bTime=System.currentTimeMillis();
System.out.println("開始時間:"+bTime);
for(int i=0;i<1000000000;i++)
aList.get(99999); //每次讀取列表末尾元素
long eTime=System.currentTimeMillis();
System.out.println("結束時間:"+eTime);
System.out.println("ArrayList隨機訪問所用時間="+(eTime-bTime)+"毫秒");
LinkedList lList=new LinkedList(); //創建LinkedList集合
System.out.println("==========LinkedList==========");
...
for(int i=0;i<1000000000;i++)
lList.get(99999); //每次讀取列表末尾元素
...
System.out.println("LinkedList隨機訪問所用時間="+(edTime-bgTime)+"毫秒");
經驗:
List就是一個線性表接口,而ArrayList、LinkedList又是線性表的兩種典型實現,ArrayList 是基於數組的線性表,而LinkedList是基於鏈表的線性表。
當對集合元素進行頻繁的添加或刪除操作時,使用LinkedList效率比較高,因爲鏈表的插入和刪除操作效率比較高。
當對集合元素進行頻繁的讀取操作時,使用ArrayList效率比較高,因爲基於數組的線性表的隨機訪問效率比較高。
7.2.3 實踐練習(一)
7.2.4 實踐練習(二)
7.3 Set集合和Iterator迭代器
7.3.1 Set集合
Set集合,類似於一個瓶子,“裝進”Set集合中的多個對象之間沒有明顯的順序。
Set集合不允許包含相同的元素,如果試圖將兩個相同的元素加入同一個Set集合中,則添加操作失敗返回false,且新元素不會被加入其集合中。
HashSet是Set接口的最常用的實現類。HashSet按Hash算法實現存儲集合中的元素,因爲其具有良好的存儲和查找性能。
Set的排列順序可能與添加順序不同,Set元素值可以是null。
示例:添加Cat對象到HashSet集合
public class Cat {
private String name;
private String color;
…
public String toString(){ //重新toString()
return "名字:"+this.name+"-"+"毛色:"+this.color;
}
}
public class HashSetTest {
public static void useHashSet(){
HashSet hs=new HashSet();
hs.add("JAVA");
hs.add(new Cat("加菲","黃色"));
hs.add(new Cat("湯姆","青色"));
hs.add(new Cat("加菲","黃色"));
hs.add("JAVA");//添加重複對象"JAVA"
hs.add(100);//添加重複對象"JAVA"
System.out.println("HashSet對象集合="+hs);
}
…..
提問:有兩條貓的名字和顏色一摸一樣,怎麼它們可以一起添加到Set集合?
分析:
這兩條貓的名字和顏色一摸一樣,但它們equals()返回值爲false,hashCode()值也不相等。所以這兩條貓不相同。
如果兩條貓相同的邏輯是它們名字和顏色相同,則可通過重寫Cat類的equals() 和hashCode() 。
示例:重寫Cat的equals() 和hashCode()
public boolean equals(Object obj){
if(obj==this){
return true;
}else{
if(obj instanceof Cat){
Cat cat=(Cat)obj;
if(this.name.equals(cat.name) && this.color.equals(cat.color))
return true;
else
return false;
}else
return false;
}
}
//重寫hashCode()方法
public int hashCode(){
return this.name.hashCode()*this.color.hashCode();
}
重寫hashCode()方法的一般規則如下:
在程序運行時,同一個對象的hashCode()方法應該返回相同的值。
當兩個對象通過equals()方法比較返回true時,這兩個對象的hashCode()方法應返回相等的值。
象中用作equals()方法比較標準的屬性,都應該用於計算hashCode的值。
7.3.2 Iterator迭代器
Iterator接口隱藏了各種Collection實現類的底層細節,該接口提供了遍歷Collection集合元素的統一編程接口。
迭代器是一種設計模式,它是一個對象,它可以遍歷並選擇序列中的對象,而開發人員不需要了解該序列的底層結構。迭代器通常被稱爲“輕量級”對象,因爲創建它的代價小。
由於Set集合中存儲的是無序的元素,因此無法在循環中按照下標獲取Set集合中的元素,所以利用Iterator接口遍歷Set集合中的元素尤爲方便。
Iterator常用方法
方法名 |
說明 |
boolean hasNext(Object o) |
如果被迭代的集合中的元素沒有遍歷完成,則返回true |
Object next() |
返回集合中的下一個元素 |
Void remove() |
將迭代器新返回的元素刪除 |
示例:Iterator迭代器應用案例
HashSet hs=new HashSet();
hs.add(1);
hs.add(new Date());
hs.add("ANDORID");
hs.add(new Cat("加菲","粉色"));
//調用HashSet對象的iterator()方法,返回Iterator實例
Iterator it=hs.iterator();
//使用while循環,循環判斷迭代器中是否還有元素
System.out.println("====使用迭代器遍歷HashSet集合=====");
while(it.hasNext()){
//獲取迭代器中的數據
Object obj=it.next();
System.out.println(obj);
}
7.3.3 實踐練習
7.4 Map集合
Map用於保存具有映射關係的數據。Map集合中保存着兩組值,一組值用於保存Map裏的key,另外一組值保存Map的value。key和value可以爲null。
key和value可以是任意類型的數據。Map的key不允許重複,即同一個Map對象的任何兩個key通過equals()方法比較總是返回false。
key和value間存在單向一對一關係,即通過指定的key總能找到唯一的、確定的value。從Map中取出數據時,只要給出指定的key,就可以取出對應的value。
HashMap是Map接口最爲常用的實現類,HashMap通過哈希碼對其內部的映射關係進行快速查找。
7.4.1 Map集合
Map接口常用方法
方法名 |
說明 |
put(K key,V value) |
向映射中添加一對key與value的映射關係 |
Object get(Object key) |
返回映射中key所對應的value。如果該映射中不包含key,則返回null |
putAll(Map map) |
將映射map所有的鍵值映射關係添加到當前映射 |
containsKey(Object key) |
如果此映射包含指定鍵的映射關係,則返回true |
containsValue(Object value) |
如果此映射將一個或多個鍵映射到指定的value,則返回true |
keySet() |
將該集合中的所有鍵對象以Set集合的形式返回 |
values() |
將該集合中的所有值對象以Collection集合的形式返回 |
remove(Object key) |
如果存在指定的鍵key,則移除該鍵的映射關係,並返回與該鍵對象對應的值對象,否則返回null |
clear() |
從此映射中移除所有映射關係 |
isEmpty() |
如果此映射未包含鍵-值映射關係,則返回true |
size() |
返回此映射中的鍵-值映射關係的數量 |
示例:HashMap應用案例
Map hm=new HashMap();
hm.put("JAVA", "DEMO");
hm.put("中國", "北京");
hm.put(1, "one");
hm.put(true,"正確" );
hm.put("中國", "上海");
System.out.println("========HashMap集合添加元素後=======");
System.out.println(hm);
System.out.println("====按照Kye獲取對應Value值====");
Object value=hm.get("中國");
System.out.println("key值爲中國對應的value值="+value);
System.out.println("HashMap集合的大小="+hm.size());
System.out.println("===遍歷HashMap集合===");
//返回存儲HashMap集合中的所有的key(鍵)的Set集合
Set set=hm.keySet();
Iterator it=set.iterator();//返回key集合的Iterator迭代器
while(it.hasNext()){//遍歷key
Object key=it.next();//得到HashMap集合中的key值
Object val=hm.get(key);//通過key得到對應的value值
System.out.println("鍵="+key+"\t"+"值="+val);
}
HashMap與Hashtable的區別
HashMap |
Hashtable |
允許出現空值、空鍵 |
不允許出現空值、空鍵 |
線程異步,效率較高 |
線程同步,效率較低 |
繼承自AbstractMap |
繼承自Dictionary |
7.4.2 實踐練習
總結:
- 所有Java集合類都位於java.util包中。與Java數組不同,Java集合不能存放基本數據類型,而只能存放對象。
- Java集合類主要由兩個接口派生而出,即Collection和Map接口。Collection和Map是Java集合框架的最上層的父接口,這兩個接口又包含其他的子接口和實現類。
- List集合代表一個元素是有序的、且可以重複的、可以爲null的集合。可以通過get(int index)取出下標爲index的元素。
- List最常見的實現類是ArrayList和LinkedList。當對集合元素進行頻繁的讀取操作時,使用ArrayList效率比較高;當對集合元素進行頻繁的添加或刪除操作時,使用LinkedList效率比較高。
- Set集合不允許包含相同的元素,Set的排列順序可能與添加順序不同,Set元素值可以是null,HashSet是Set接口的最常用的實現類。可以通過重寫類的equals()和hashCode()方法定義對象相等的邏輯。
- Iterator迭代器提供了遍歷Collection集合元素的統一編程接口。
- Map用於保存具有映射關係的數據。Map集合中保存着兩組值,一組值用於保存Map裏的key,另外一組值保存Map的value。key和value可以爲null。
- Map接口的put(K key,V value)用於向映射中添加一對key與value的映射關係,get(Object key)用於返回映射中key所對應的value。