java集合(上)_Collection集合

本文總結java單列集合,單列集合頂層接口是Collection。剛接觸java集合時知道java集合可以裝載任意類型的對象,是一種功能強大的容器,逐漸學習後發現java集合框架層次明確,每個容器都有自己的特殊用途,學習時要掌握並理清集合的共性方法和每種容器的特殊方法。

集合
集合用於存儲對象,長度可變,存儲的對象元素類型可不一致。集合只能存儲對象,不能存儲基本數據類型。
java集合框架有2個頂層接口,Collection是單列集合的頂層接口,Map是雙列集合的頂層接口。


圖解:
1. 虛線框內的都是接口,實線框內的是類。
2. Map指向Collection的虛線代表Map雙列集合可以通過keySet()和entrySet()方法獲得鍵值和映射關係的單列集合。
3. Collection指向Iterator接口的虛線表示,Collection子類對象都可以通過iterator()方法獲取迭代器對象。
4. 集合框架有2個常用工具類,Collections和Arrays,裏面封裝了若干實用的靜態方法。
5. 集合體系是存儲對象的容器,之所以會出現圖中這麼多的容器,是因爲每一個容器對數據的存儲方式(也就是數據結構)都有不同。

Collection類中集合共性方法

1. 添加元素
void add(Object obj), 參數類型是Object, 以便於接收任意類型。
boolean addAll(Collection <? extends E> c), 將集合對象c整個添加到調用此方法的Collection對象中,如果調用此方法的Collection對象存儲的元素類型是E,那c可以是存儲E的任意子類對象的集合;如果調用此方法後,集合內容發生變更,返回true.
集合中存儲的是對象的引用地址。

2. 獲取集合長度
int size()

3.  打印集合
System.out.println(c).

4. 刪除元素
boolean remove(Object obj), 如果刪除了一個元素,返回true.
boolean removeAll(Collection<?> c), 集合中刪除指定集合c中的所有元素,如果調用此方法後集合內容變更,返回true.
boolean retain(Collection<?> c),  保留此集合與指定集合c的交集,無交集時,此集合變爲空,如果調用方法後此集合內容發生改變,返回true.

5. 清空集合
void clear()

6. 判斷元素
boolean contains(Object obj), 判斷集合中是否包含obj對象
boolean isEmpty(), 判斷集合是否爲空.

7. 遍歷集合
java將集合元素的共性取出方式(都是先判斷再取出),抽象爲Iterator接口。
每一個容器的數據結構不同,取出動作的細節也不一樣,所以將取出方式定義在集合內部,這樣可以直接訪問集合內部的元素。
每個集合子類中都有一個實現Iterator接口的內部類(非匿名),集合對外提供iterator()方法,iterator()方法返回一個此內部類的對象,也就是此集合的迭代器。

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo1 {

	private static ArrayList al2;
	public static void main(String[] args) {
		baseMethod();
	}
	public static void baseMethod(){
		Collection al=new ArrayList();
		//添加元素
		al.add("day01");
		al.add("day02");
		al.add("day03");
		al.add("day04");
		//打印集合
		sop("原集合:"+al);
		//打印集合長度
		sop("原集合長度:"+al.size());
		//刪除元素
		sop("是否刪除了day01元素:"+al.remove("day01"));//刪除了"day01",返回true
		sop("是否刪除了day111元素:"+al.remove("day111"));//集合中沒有此元素,沒法刪除,原集合不變,返回false
		//清空集合
		//al.clear();
		//判斷元素
		sop("是否存在day02元素"+al.contains("day01"));
		sop("集合是否爲空:"+al.isEmpty());
		
		//獲取2個集合的交集元素
		al2 = new ArrayList();
		al2.add("day02");
		al2.add("day03");
		al2.add("day05");
		al2.add("day06");
		sop("原集合與a12是否有交集:"+al.retainAll(al2));
		sop("原集合與a12的交集元素:"+al);
		
		//集合元素迭代
		for(Iterator it=al.iterator();it.hasNext();){
			sop(it.next());
		}
	}
	public static void sop(Object obj){
		System.out.println(obj);
	}
}
運行結果:
原集合:[day01, day02, day03, day04]
原集合長度:4
是否刪除了day01元素:true
是否刪除了day111元素:false
是否存在day02元素false
集合是否爲空:false
原集合與a12是否有交集:true
取交集後,al集合變爲:[day02, day03]
day02
day03
注:jdk1.5版本起,引入了泛型機制,編譯上述程序時會報“ 注意:CollectionDemo1.java使用了未經檢查或不安全的操作。注意:要了解詳細信息,請使得-xlint:unchecked重新編譯。”,是因爲上面程序中使用ArrayList集合時未指定泛型,存在安全隱患

Collection接口有2個子接口:List, Set.
List: 元素是有序的,元素可以重複,該集合體繫有索引。
Set; 元素無序,元素不可重複。

List集合
與Collection接口相比,凡是可以操作角標的方法都是該體系的特有的方法,元素角標從0開始。

1. 增加元素
boolean add(index,element),  boolean addAll(index,collection)

2. 刪除元素
boolean remove(index)

3. 修改
E set(int index, E e), 用指定元素替換列表中指定位置的元素,返回替換前的元素。

4. 查詢
E get(int index)
List<E> subList(int from, int to)

5. 迭代器
Iterator iterator()和ListIterator listIterator():
ListIteratror對象是List集合特有的迭代器,只能通過listIterator()方法獲取,List集合中也還有iterator()方法,但調用此方法返回的是Iterator接口的直接內部子類對象。
Iterator迭代器的侷限性:在迭代時,不可以通過集合對象的方法操作集合中的元素,因爲迭代器與對象本身同時操作集合時會發生異常CurrentModificatonException, 所以在迭代時,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能對元素進行判斷、取出和刪除。
ListIterator解決了這個問題,ListIterator是Iterator的子接口,該迭代器中可以對元素進行添加、修改。
ListIterator迭代器中還可以逆向遍歷集合元素,使用方法hasPrevious()和previous()方法。

List有3個子類:ArrayList, LinkedList, Vector

ArrayList: 從jdk 1.2版本開始的,底層數據結構是數組,非線程同步的,特點是查詢速度快,但是增刪稍慢(元素多時影響大)。默認長度是10,超過時,先copy原數組,再創建新數組,50%擴展空間。

LinkedList: 從jdk1.2版本開始的,底層使用的是鏈表數據結構,非線程同步,特點是增刪速度快,查詢稍慢。
LinkedList的特有方法
addFirst(), addLast(), 在鏈表頭或尾添加元素;
getFirst(), getLast(), 獲取元素,但不刪除元素;
removeFirst(), removeLast(), 獲取元素,並刪除元素,可用來遍歷刪鏈表;
---上面的get和remove方法,如果集合中沒有元素會拋出NoSuchElementException異常
offerFirst(), offerLast(), 在表頭或表尾插入元素;
peekFirst(), peekLast(), 獲取表頭或表尾元素,但不刪除元素;
pollFirst(), pollLast(), 獲取表頭或表尾元素,並刪除元素。
---上面幾個是jdk1.6版本纔有的方法,如果集合中沒有元素不會拋出異常,返回null.

Vector: 從jdk1.0版本開始的,先與集合框架存在, 底層是數組結構,線程同步,與ArrayList功能重複,被ArrayList替代了,需要判斷鎖,效率慢。默認長度是10,超過時100%擴展空間。 

Set集合
元素是無序的,存入和取出的順序不一定一致,元素不可以重複。

Set集合常見子類-HashSet
HashSet底層數據結構是Hash表,非線程同步。
往HashSet集合中存儲元素時,是先調用元素的hashCode()判斷哈希值大小,哈希值一樣時,再調用元素的equals()方法判斷元素內容。如果2個對象哈希值一樣,內容不一樣,會在一連續地址值中順沿存放2個元素。如果哈希值不一樣,不會再調用equals()方法。
hashCode()是Object類的方法,返回對象的哈希值,可被複寫;Object類對象的哈希值就是地址值,子類複寫後就不一定是地址值了。

HashSet具體存儲原理-哈希表
     想查找一個集合中是否包含有某個對象,通常想到的是逐一取出集合中每個元素與要查找的元素使用equals()方法進行比較, 如果集合中有一萬個元素,這種方法效率很低。
     哈希算法可以大大提高在集合中查找元素的效率。這種算法採用對某個數字n進行取餘的方式將元素哈希值進行劃分,將集合分成若干存儲區域,根據一個對象的哈希值就可以確定該對象應該存儲在哪個區域,確定存儲區域後,只需取出該區域的各個元素與要查找的對象使用equals方法進行比較即可,不用遍歷集合中所有元素,從而提高了效率。

對象要存儲在HashSet集合中,最好是複寫hashCode()方法和equals()方法。HashSet集合的方法contains()和remove(),執行原理也是依賴這2個方法(List集合只依賴equals()方法)。
注:當一個對象被存儲進HashSet集合以後,就不能修改這個對象中那些參與計算哈希值的字段了,否則,對象修改後的哈希值與最初存儲進HashSet集合中的哈希值就不同了,這樣,使用contains方法在HashSet中檢索該對象時,就會找不到這個對象,也就無法單獨刪除此對象,造成內存泄露(java雖然的內存回收機制,但仍有內存泄露,這就是一個例子)。

Set集合常見子類-TreeSet
TreeSet可以對集合中元素按照元素自然順序(默認順序)進行排序,或者根據創建 TreeSet 時提供的Comparator比較器進行排序,底層數據結構是二叉樹。TreeSet集合中的add(),contains()和remove()方法依據元素的自然順序或TreeSet集合自身的Comparator比較器。
TreeSet排序的第1種方式:讓元素自身具備比較性,元素需要實現Compareable接口,並覆蓋compareTo()方法。
TreeSet排序的第2種方式:讓集合自身具備比較性,當元素不具備比較性,或具備的比較性不是所需要的,可以使用此方式,集合的比較性會覆蓋元素的比較性。

具體是定義比較器類,將該比較器類對象作爲參數傳遞給TreeSet()的構造函數,比較器類需實現Comparator()接口,並覆蓋compare(obj1,obj2)方法。

下面是一個用第一種方式解決IP地址排序的例子:

/*
需求:用TreeSet實現IP地址排序,用第1種方式實現,IP地址封裝成IPAdress類,讓IPAdress本身具有比較性
*/
import java.util.Iterator;
import java.util.TreeSet;
 public class IpTest {
         public static void main(String[] args) {
                 TreeSet ts=new TreeSet();
                 ts.add(new IpAdress("61.54.231.245"));
                 ts.add(new IpAdress("61.54.231.9"));
                 ts.add(new IpAdress("61.54.231.246"));
                 ts.add(new IpAdress("61.54.231.48"));
                 ts.add(new IpAdress("61.53.231.249"));                
                 Iterator it=ts.iterator();
                 while(it.hasNext()){
                         IpAdress ip=(IpAdress)it.next();
                         ip.Show();        
                 }
         }
 }
 class IpAdress implements Comparable{        
         private String adress;
         public IpAdress(String adress){
                 this.adress=adress;
         }
         public int compareTo(Object obj) {
                 if(!(obj instanceof IpAdress)){
                         throw new RuntimeException("不是IP地址");
                 }
                 IpAdress p=(IpAdress)obj;
                 String[] sp1=this.adress.split("\\.");
                 String[] sp2=p.adress.split("\\.");
                 for(int i=0;i<sp1.length;i++){
                         int x=Integer.parseInt(sp1[i])-Integer.parseInt(sp2[i]);
                         if(x!=0){
                                 return x;
                         }
                 }
                 return 0;                
         }
         public void Show(){
                 System.out.println(adress);
         }         
 }
運行結果就是:
61.53.231.249
61.54.231.9
61.54.231.48
61.54.231.245
61.54.231.246





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章