【java基礎】——集合類(上)


一、集合框架類概述

定義:集合框架,是爲了表示和操作集合而規定的一種統一的標準的體系結構。任何集合框架都包含三大內容 :對外的接口、接口的實現和集合運算的算法。
  • 接口:即表示集合的抽象數據類型。接口提供了讓我們對集合所表示的內容進行單獨操作的可能。
  • 實現:也就是集合框架中接口的具體實現。實際它們就是那些可複用的數據結構。
  • 算法:在一個實現了某個集合框架中的接口對象上完成某種有用的計算方法,例如查找、排序等等。

1、集合類的由來

面嚮對象語言對事物的體現都是以對象的形式來,爲了方便對多個對象的操作,對對象進行存儲,集合就是存儲對象最常用的一種方式。

2、集合和數組的異同

相同之處:
  • 集合和數組都是容器。
  • 集合和數組中存儲的都是對象的引用(內存地址值)。
不同之處:
  • 數組雖然也可以存儲對象,但長度是固定的;集合長度的可變的。
  • 數組只能存儲一種類型的對象,集合可以存儲任意類型的對象。
  • 數組中可以存儲基本數據類型,集合只能存儲對象。

3、集合框架體系的內容

java集合框架的體系內容可以見如下圖:

java集合框架圖簡析如下:
  • 集合接口:6個接口,(短虛線表示),表示不同類型的集合,是集合框架的基礎。
  • 抽象類:5個抽象類,(長虛線表示),對幾個接口的部分實現,可擴展爲自定義集合類。
  • 實現類:8個實現類,(實現表示),對接口的具體實現。
在很大程度上,一旦理解了接口,也就理解了框架,雖然總要創建接口特定的實現,但訪問實際集合的方法應該限制在接口方法的使用上,因此,Java集合類允許我們更改基本數據結構而不必改變它的代碼。
  • Collection接口是一組允許重複的對象。
  • Set接口繼承了Collection,但不允許重複,元素是無序的,使用自己內部的一個排列機制。
  • List接口繼承了Collection,允許重複,元素是有序的,以元素安插的順序來放置元素,不會重新排列。
  • Map接口是一組成對的鍵-值對象,Map中的鍵是唯一的,不允許重複,擁有自己的內部排列機制。
  • 注:容器中的元素都爲Object類型,從容器取得元素時,必須把它轉換成原來的類型。

二、Collection<E>接口

當用於表示任何對象或者元素組,想要儘可能以常規 方式處理一組元素時,就使用這一接口。Collection下有兩個常用子接口:List<E>(列表)、Set<E>(集)。

1、Collection接口中的常用方法:

a、添加方法
  • boolean add(E e) 添加一個元素。add方法的參數類型是 Object 。以便於接收任意類型對象。
  • boolean addAll(Collection<? extends E> c) 添加另一集合內所有元素
b、刪除方法
  • boolean remove(Object o);刪除一個元素
  • boolean removeAll(Collection<?> c)僅移除本集合中另一集合也有的元素,即移除本集合中與另一集合的交集
  • void clear();清空集合
c、判斷方法
  • boolean contains(Object o) 判斷是否包含某個元素
  • boolean containsAll(Collection<?> c)判斷是否包含另一集合中的所有元素
  • boolean isEmpty()判斷集合是否爲空  //其實它是在調用size方法
d、獲取方法
  • Iterator<E> iterator()迭代。返回在此集合的元素上進行迭代的迭代器。
  • int size()獲取集合長度
  • boolean retainAll(Collection<?> c)僅保留此集合中另一集合也有的元素,即保留本集合與另一集合的交集
e、Collection轉換爲Object數組
  • Object[] toArray() :返回一個內含集合所有元素的array
  • Object[] toArray(Object[] a) :返回一個內含集合所有元素的array。運行期返回的array和參數a的型別相同,需要轉換爲正確型別。
  • 此外,我們還可以把集合轉換成其它任何類型的數組。但是,我們不能直接把集合轉換成基本數據類型的數組,因爲集合必須持有對象。
以下是對Collection基本方法的演示:
import java.util.*;
/*Collection集合常用方法演示*/
class  CollectionDemo
{
	public static void main(String[] args) 
	{
		method_get();
	}
	public static void method_get()
	{
		Collection list1 = new ArrayList();
		/*==================1、添加方法演示==================*/
		//添加元素。add()
		list1.add("huangxiang01");
		list1.add("huangxiang02");
		list1.add("huangxiang03");
		list1.add("huangxiang04");
		//添加另一集合的所有元素。addAll()
		Collection list2 = new ArrayList();
		list2.add("huang55");
		list2.add("huang56");
		list2.add("huang57");
		list2.add("huangxiang04");
		//將list2集合的中元素全部添加到list1集合中。
		//list1.addAll(list2);
		
		/*==================2、刪除方法演示==================*/
		//刪除元素。remove()
		//list1.remove("huangxiang01");
		//刪除本集合中另一集合也有的元素
		//list1.removeAll(list2);
		//清空集合
		//list1.clear();
		
		/*==================3、判斷方法演示==================*/
		//判斷是否包含某個元素
		Sop(list1.contains("huangxiang03"));
		//判斷是否包含另一集合中的所有元素
		Sop(list1.containsAll(list2));
		//判斷集合是否爲空
		Sop(list1.isEmpty());
		
		/*==================4、獲取方法演示==================*/
		//迭代器
		Iterator it = list1.iterator();
		while(it.hasNext()){
			Sop(it.next());
		}
		//獲取集合長度
		Sop(list1.size());
		//獲取本集合與另一集合的交集
		Sop(list1.retainAll(list2));
		
		/*==================5、數組轉換方法演示==================*/
		//返回一個內含集合所有元素的array
		list1.toArray();
		//
	}
	public static void Sop(Object obj){
		System.out.println(obj);
	}
}
	

2、迭代器Iterator

迭代器是取出集合中元素的一種方式,Collection中實現了iterator()方法,所以其每一個子集合都具備迭代器。
a、迭代器常見操作:
  • hasNext():如果有下一個元素,返回真
  • next():取出下一個元素
  • remove():移除
  • 注意:在迭代循環中,next每調用一次,就要用hasNext()判斷一次。
b、迭代注意事項
  • 迭代器在Collection接口中是通用的,他替代了Vector類中的枚舉。
  • 迭代器的next()方法是自動向下取元素,要避免出現NoSuchElementException。
  • 迭代器的next()方法返回值類型是Object,要注意類型轉換。

三、List<E>接口

List接口繼承了Collection結構以定義一個允許重複項的有序集合。該接口不但能夠對列表的一部分進行處理,還添加了面向位置的操作。凡是可以對角標進行操作的方法都是該體系特有的方法

1、List接口的常用子類對象

  • ArrayList:底層的數據結構使用的是數組。特點:查詢速度很快。但是增刪稍慢,線程不同步。
  • LinkedList:底層使用的是鏈表數據結構。特點:增刪速度很快。查詢較慢。
  • Vector:底層是數組數據結構。線程同步。被ArrayList替代。

2、List接口的特有方法

  • void add(int index,E element)在列表的指定位置插入指定元素。
  • boolean addAll(int index, Collection<? extends E> c) 將指定 collection 中的所有元素都插入到列表中的指定位置。
  • E remove(int index) 移除列表中指定位置的元素。
  • E set(int index, E element) 用指定元素替換列表中指定位置的元素,返回以前在指定位置的元素。
  • E get(int index) 返回列表中指定位置的元素。
  • List<E> subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之間的部分列表。
  • ListIterator<E> listIterator() 返回此列表元素的列表迭代器。
  • ListIterator<E> listIterator(int index) 從列表的指定位置開始返回列表中元素的列表迭代器。

3、ArrayList類

ArrayList類封裝了一個動態再分配的Object[]數組。每一個ArrayList對象都有一個capacity,這個capacity表示存儲列表中元素的數組的容量。當元素添加滿時,它會自動擴容。在jdk1.6中,自動擴容爲增加i*3/2+1,在1.7及1.8中,爲1.5倍擴容。
下面是ArrayList的一些常用方法演示:
import java.util.*;
//ArrayList 最基本的用法
public class ArrayListTest1{
	public static void main(String[]args){
		//如何創建對象
		List<Integer> list = new ArrayList<Integer>();
		//向ArrayList中添加元素
		list.add(25);
		list.add(26);
		list.add(12);
		list.add(28);
		//得到Arraylist中添加了多少個元素
		System.out.println(list.size());
		System.out.println("===================華麗的分割線================");
		//如何得到集合當中的第幾個元素
		Integer num = list.get(1);
		System.out.println(num);
		System.out.println("===================華麗的分割線================");
		//如何遍歷ArrayList。
		//第一種方法:for循環
		for(int i = 0;i < list.size();i++){
			System.out.println(list.get(i));
		}
		System.out.println("===================華麗的分割線================");
		//第二種方法,迭代器
		Iterator<Integer> it = list.iterator();
		while(it.hasNext()){
			Integer data = it.next();
			System.out.println(data);
		}
		System.out.println("==========================華麗的分割線==========================");
		//第三種方法:foreach循環
		for(Integer i : list)
			System.out.println(i);
	}	
}
import java.util.*;
//ArrayList提供了remove(int index),remove(Object obj)兩個方法刪除
public class ArrayListTest2{
	public static void main(String[] args){
		ArrayList<Integer> list = new ArrayList<>(5);
		/*list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);*///list集合中的添加方法,逐個添加
		Collections.addAll(list,1,2,3,4,5);//Collections提供的addAll方法
		//addAll(list,1,2,3,4,5);//自定義的批量添加addAll方法
		System.out.println(list);
		//刪除元素:方法1
		list.remove(2);//明確的刪除第幾個元素
		System.out.println(list);
		System.out.println("==================華麗的分割線===================");
		//刪除元素:方法2
		list.remove(new Integer(4));//明確的刪除哪一個元素
		System.out.println(list);
		System.out.println("====================華麗的分割線=================");
		//刪除所有元素:用循環
		/*while(list.size()!=0)
			list.remove(0);
		System.out.println(list);*/
		//刪除所有元素:用clear()方法
		list.clear();
		System.out.println(list);
	}
	public static void addAll(List<Integer> list,Integer...data){
		for(Integer i : data)
			list.add(i);
	}
}
import java.util.*;
//remove(Object obj)是如何找到元素的,如何刪除你的元素的
public class ArrayListTest3{
	public static void main(String[] args){
		ArrayList<Integer> list = new ArrayList<>();
		Integer i1 = new Integer(5);
		Integer i2 = new Integer(5);
		list.add(i1);
		System.out.println(list.size());//結果是1
		list.remove(i2);
		System.out.println(list.size());//結果是0
		//結果:說明ArrayList的remove(Object obj) 完全尊重equals比較返回的結果。
		System.out.println("===================華麗的分割線====================");
		ArrayList<Teacher> list2 = new ArrayList<>();
		Teacher tea1 = new Teacher("zhangsan",25);
		Teacher tea2 = new Teacher("zhangsan",25);
		list2.add(tea1);
		System.out.println(list2.size());//結果爲1
		list2.remove(tea2);
		System.out.println(list2.size());//結果爲1
		//在複寫之前結果爲1,即相同的元素沒有被刪除。這是因爲在Object中的eaquls方
		//法其實就是==運算
		//複寫equals方法之後,相同的元素被刪除。
	}
} 
class Teacher{
	private String name;
	private int age;
	
	public Teacher(String name,int age){
		this.name = name;
		this.age = age;
	}
	@Override
	public boolean equals(Object obj){
		System.out.println("我被執行啦");
		//做一些健壯性判斷
		if(obj == null) return false;
		if(!(obj instanceof Teacher)) return false;
		if(obj == this) return true;
		Teacher t1 = this;
		Teacher t2 = (Teacher)obj;
		return t2.name.equals(t2.name) && (t1.age == t2.age);
	}
}
import java.util.*;
public class ArrayListTest4{
	public static void main(String[] args){
		List<Integer> list = new ArrayList<>();
		Collections.addAll(list,1,2,3,4,5);
		//需求:刪除所有小於3的數
		Iterator<Integer> it = list.iterator();
		/*
		 java.util.ConcurrentModificationException併發修改異常。
		 按照下面這種寫法會發生該異常。在迭代器遍歷ArrayList的過程當中,絕對不允許
		 對集合整體進行任何添加刪除操作。(除了刪除不成功的)
		while(it.hasNext()){
			Integer num = it.next();
			if(num<3)
				list.remove(num);
		}
		*/
		while(it.hasNext()){
			Integer num = it.next();
			if(num<3)
				it.remove();
		}
		System.out.println(list.size());
	}
}
//模擬ArrayList的主要方法底層實現
public class ArrayListTest5{
	public static void main(String[] args){
		MyList list = new MyList();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		System.out.println(list.getSize());
	}
}
class MyList{
	private Object[] data;
	private int size;//用戶存放了多少元素進來
	
	//根據用戶指定的容量,初始化底層的數組的構造方法
	public MyList(int length){
		data = new Object[length];
	}
	//默認的構造方法,它共享了有參的構造方法,默認10個空
	public MyList(){
		this(10);
	}
	//用來得到已經存放的元素個
	public int getSize(){
		return size;
	}
	
	//得到第幾個元素的方法
	public Object get(int i){
		return data[i];
	}
	//添加元素的方法
	public void add(Object obj){
		//如果底層的數組存儲空間已經滿了
		if(data.length == size){
			Object[] temp = new Object[size*3/2+1]; //找到一個更大的新筐
			System.arraycopy(data,0,temp,0,size);//將老筐裏面的棒子放到新筐裏
			data = temp;//背上新筐(老筐留給收垃圾的)
		}
		data[size++] = obj;
	}
	//刪除第幾個元素的方法
	public void remove(int x){
		System.arraycopy(data,x+1,data,x,size-x-1);
		size--;
		/*
			0 1 2 3 4   要刪除的是下標2,那麼其實就是從下標3開始向下標2複製元素 
			0 1 3 4		總共複製5-2-1.
		*/
	}
	//刪除指定的那個元素的方法
	public void remove(Object obj){
		for(int i = 0;i<size;i++){
			if(obj.equals(data[i]))
				remove(i);
		}
	}
}


4LinkedList類

在LinkedList類中,添加了一些處理兩端元素的方法。
  • void addFirst(Object o): 將對象o添加到列表的開頭
  • void addLast(Object o):將對象o添加到列表的結尾
  • Object getFirst(): 返回列表開頭的元素
  • Object getLast(): 返回列表結尾的元素
  • Object removeFirst(): 刪除並且返回列表開頭的元素
  • Object removeLast():刪除並且返回列表結尾的元素
  • LinkedList(): 構建一個空的鏈接列表
  • LinkedList(Collection c): 構建一個鏈接列表,並且添加集合c的所有元素
通過對這些新方法的使用,我們可以輕鬆的把 LinkedList當成一個棧堆。隊列、或者其它面向端點的數據結構。
在JDK1.6以後,出現了替代方法。
  • offFirst();替代addFirst
  • offLast();替代addLast
  • peekFirst();替代getFirst
  • peekLast();替代getLast
  • pollFirst();替代removeFirst
  • pollLast();替代removeLast
下面舉例一個使用LinkedList模擬一個棧堆或隊列的數據結構。
/*
使用LinkedList模擬一個堆棧或者隊列數據結構。

堆棧:先進後出  如同一個杯子。
隊列:先進先出 First in First out  FIFO 如同一個水管。

*/
import java.util.*;

class LinkedListTest
{
	public static void main(String[] args) 
	{
		LinkedList l=new LinkedList();
		l.addFirst("java01");
		l.addFirst("java02");
		l.addFirst("java03");
		l.addFirst("java04");
		l.addFirst("java05");
	
		//堆棧輸出
	//	stack(l);
		
		//隊列輸出
		queue(l);
	}

	//堆棧
	public static void stack(LinkedList l)
	{
		while (!l.isEmpty())
		{
			sop(l.removeFirst());
		}
	}
	//隊列
	public static void queue(LinkedList l)
	{
		while(!l.isEmpty())
		{
			sop(l.removeLast());
		}
	}

	//輸出
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}

5、ListIterator

ListIterator接口繼承了Iterator接口,是List集合的特有的。以支持添加和更改底層集合中的元素。還支持雙向訪問。ListIterator沒有當前位置。光標位於調用previous和next方法的返回值之間。
ListIterator特有的方法:
  • add(obj); 將obj添加到當前位置的前面
  • set(obj); 用obj替代next或者previous方法訪問的上一個元素。如果上次調用後列表結構被修改了。將拋出異常。
  • hasPrevious();  判斷前面有沒有元素
  • previous();  返回上一個元素對象
注:“正常情況下,不用ListIterator改變某次遍歷集合元素的方向 — 向前或者向後。雖然在技術上可以實現,但previous() 後立刻調用next(),返回的是同一個元素。把調用 next()和previous()的順序顛倒一下,結果相同。”
“我們還需要稍微再解釋一下 add() 操作。添加一個元素會導致新元素立刻被添加到隱式光標的前面。因此,添加元素後調用 previous() 會返回新元素,而調用 next() 則不起作用,返回添加操作之前的下一個元素。”

6、Vector類

該類中帶有elements的方法都是該類特有的方法。
Vector類有特有的元素取出方式:枚舉是其取出元素的方式,因爲其名稱及方法名過長,被迭代器給取代了。
該類的特有方法如下:
  • addElement(obj);//添加元素,相當於add(obj);
  • Enumerationelements();//Vector特有取出方式(枚舉)
  • hasMoreElements();//相當於Iterator的hasNext()方法
  • nextElements();//相當於Iterator的next()方法
Vector類應用舉例:
Vector v=new Vector();
	for(Enumeration e=v.elements();e.hasMoreElements();)
{
	System.out.println(e.nextElements());
}

四、Set<E>接口

Set接口繼承了Collection接口,而且它不允許集合中存在重複項,每個具體的的Set實現類依賴添加的對象的equals()方法來檢查其唯一性,Set接口沒有引入新方法,其方法和Collection一樣,不過行爲不同。瞭解Set類,首先要對散列表(hash table也稱哈希表)和樹集有所瞭解

1、散列表(哈希表)

衆所周知,有一種數據結構可以快速的查找所需要的對象,這就是散列表,散列表爲每個對象計算一個整數,稱爲散列碼(hash code)。散列碼是由對象的實例域產生的一個整數。更準確地說,具有不同數據域的對象將產生不同的散列碼。如果我們要自定義類,就要負責實現這個類的hashCode方法,另外自己實現的hashCode方法英語equals方法兼容,即如果a.equals(b)的值爲true,則a與b必須具有相同的散列碼。在java中,HashSet是基於散列表的集。

2、樹集

樹集是一個有序集合。可以以任意順序將元素插入到集合中。在對集合進行遍歷時,每個值將自動的按照排序後的順序呈現。在java中,TreeSet的底層結構是樹結構。

3、Set概述

Set<E>:元素是無序的,存入和取出的順序不一定一致。元素不可以重複!主要實現類有HashSet和TreeSet。
  • HashSet:底層數據結構是哈希表,線程不同步。其保證元素唯一性的原理是:判斷元素的hashCode是否相同,如果相同會繼續判斷元素的equals方法。
  • TreeSet:可以對Set集合中的元素進行排序。默認按照字母的自然順序排序。底層數據結構是二叉樹。保證元素唯一性的依據是:compareTo方法返回true。當compareTo方法無法滿足需求時,可以採用自定義比較器,實現Comparator接口並覆蓋其中的compare()方法來實現。

4、Comparable接口和Comparator接口

在“集合框架”中有兩種比較接口:Comparable接口和Comparator接口。像String和Integer等Java內建類實現 Comparable接口以提供一定排序方式,但這樣只能實現該接口一次。對於那些沒有實現Comparable接口的類、或者自定義的類,您可以通過 Comparator接口來定義您自己的比較方式。
  • Compareable接口

在java.lang包中,Comparable接口適用於一個類有自然順序的時候。假定對象集合是同一類型,該接口允許您把集合排序成自然順序。


a、int compareTo(Object o): 比較當前實例對象與對象o,如果位於對象o之前,返回負值,如果兩個對象在排序中位置相同,則返回0,如果位於對象o後面,則返回正值

在 Java 2 SDK版本1.4中有二十四個類實現Comparable接口。下表展示了8種基本類型的自然排序。雖然一些類共享同一種自然排序,但只有相互可比的類才能排序。

排序
BigDecimal,BigInteger,Byte, Double, Float,Integer,Long,Short
按照數字大小排序
Character
按 Unicode 值的數字大小排序
String
按字符串中字符 Unicode 值排序

利用Comparable接口創建您自己的類的排序順序,只是實現compareTo()方法的問題。通常就是依賴幾個數據成員的自然排序。同時類也應該覆蓋equals()和hashCode()以確保兩個相等的對象返回同一個哈希碼。

b、Comparator接口

若一個類不能用於實現java.lang.Comparable,或者您不喜歡缺省的Comparable行爲並想提供自己的排序順序(可能多種排序方式),你可以實現Comparator接口,從而定義一個比較器。


  • int compare(Object o1, Object o2): 對兩個對象o1和o2進行比較,如果o1位於o2的前面,則返回負值,如果在排序順序中認爲o1和o2是相同的,返回0,如果o1位於o2的後面,則返回正值
    “與Comparable相似,0返回值不表示元素相等。一個0返回值只是表示兩個對象排在同一位置。由Comparator用戶決定如何處理。如果兩個不相等的元素比較的結果爲零,您首先應該確信那就是您要的結果,然後記錄行爲。”
  • boolean equals(Object obj): 指示對象obj是否和比較器相等。“該方法覆寫Object的equals()方法,檢查的是Comparator實現的等同性,不是處於比較狀態下的對象。

5、HashSet類

a、概述:HashSet實現了Set接口,不保證Set的迭代順序,允許使用null元素。該類的實現是不同步的。該類的構造方法如下:
  • HashSet():構造一個新的空 set,其底層 HashMap 實例的默認初始容量是 16,加載因子是 0.75。
  • HashSet(Collection<? extendsE> c):構造一個包含指定 collection 中的元素的新 set。
  • HashSet(int initialCapacity): 構造一個新的空 set,其底層 HashMap 實例具有指定的初始容量和默認的加載因子(0.75)。
  • HashSet(int initialCapacity, float loadFactor):構造一個新的空 set,其底層 HashMap 實例具有指定的初始容量和指定的加載因子。
b、Hashset類的實現:HashSet是基於HashMap實現的。其底層採用HashMap來保存元素,查看HashSet的源代碼我們可以發現,HashSet的絕大部分方法都是通過調用HashMap的方法來實現的。因此HashSet和HashMap在本質上是相同的。
c、HashSet實現自定義類的元素唯一性的代碼實例:
import java.util.*;
/*
需求:往HashSet中存入自定義對象。姓名和年齡相同是同一個人。爲重複元素。應去除。
思路:1、對人進行描述,將人的一些屬性等封裝
      2、定義一個HashSet集合,存儲對象
      3、取出。
*/
public class HashSetTest2{
	public static void main(String[]args){
		//創建一個HashSet集合
		HashSet<Person> hs = new HashSet<Person>();
		//向集合中添加元素,這裏添加了兩個相同元素
		hs.add(new Person("zhangsan",25));
		hs.add(new Person("lisi",25));
		hs.add(new Person("wangwu",25));
		hs.add(new Person("zhangsan",25));
		hs.add(new Person("wangwu",25));
		//返回迭代器
		Iterator<Person> it = hs.iterator();
		//迭代取出元素
		while(it.hasNext()){
			Person p = it.next();
			System.out.println(p.getName()+"......."+p.getAge());
		}
	}
}
//自定義類
class Person{
	private String name;
	private int age;
	//構造方法初始化
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
	//複寫hashCode方法
	@Override
	public int hashCode(){
		return name.hashCode()+age;
	}
	//複寫Obeject類中的equals方法
	public boolean equals(Object obj){
		//健壯性判斷
		if(obj == null) return false;
		if(!(obj instanceof Person)) return false;
		if(obj == this)  return true;
		Person p = (Person)obj;
		//這裏的equals方法是字符串的equals方法。
		return this.name.equals(p.name) && this.age == p.age;
	}
	
}


6、TreeSet

a、TreeSet的構造方法摘要
  • TreeSet():構造一個新的空 set,該 set 根據其元素的自然順序進行排序。
  • TreeSet(Collection<? extendsE> c):構造一個包含指定 collection 元素的新 TreeSet,它按照其元素的自然順序進行排序。
  • TreeSet(Comparator<? superE> comparator):構造一個新的空 TreeSet,它根據指定比較器進行排序。
  • TreeSet(SortedSet<E> s):構造一個與指定有序 set 具有相同映射關係和相同排序的新 TreeSet。
b、下面通過一個實例來描述TreeSet實現排序的兩種方式:
import java.util.*;
/*
	創建兩個Item對象的樹集。第一個按照部件編號排序,這是Item對象的默認順序,
	第二個通過使用一個定製的比較器來按照描述信息排序。
*/
public class TreeSetTest1{
	public static void main(String[] args){
		//第一個TreeSet集合,按照默認排序編號進行排序。compareTo()
		SortedSet<Item> parts = new TreeSet<Item>();
		parts.add(new Item("Tosater",1234));
		parts.add(new Item("Widget",4562));
		parts.add(new Item("Modem",9912));
		System.out.println(parts);
		//第二個Set集合,按照自定義比較器按照描述信息排序
		SortedSet<Item> sortByDescription = new TreeSet<Item>(new 
			Comparator<Item>(){
				//匿名內部類實現Comparator接口
				public int compare(Item a,Item b){
					String descrA = a.getDescription();
					String descrB = b.getDescription();
					return descrA.compareTo(descrB);
				}
			});
			//打印排序後的結果
			sortByDescription.addAll(parts);
			System.out.println(sortByDescription);
	}
}
/*
	創建一個待描述信息和部件編號的類
*/
class Item implements Comparable<Item>{
	private String description;
	private int partNumber;
	/**
		構造器初始化
		@aDescription  Item的description
		@aPartNumber   Item的部件編號(part number)
	*/
	public Item(String aDescription,int aPartNumber){
		description = aDescription;
		partNumber = aPartNumber;
	}
	/**
		獲取Item的描述信息
		@return description 返回值
	*/
	public String getDescription(){
		return description;
	}
	@Override
	public String toString(){
		return "[description=" + description + ",partNumber" + partNumber+"]";
	}
	@Override
	public boolean equals(Object otherObject){
		//健壯性判斷
		if(this == otherObject) return true;
		if(otherObject == null) return false;
		if(getClass() != otherObject.getClass()) return false;
		
		Item other = (Item)otherObject;
		return 
		description.equals(other.description) && partNumber == other.partNumber;
	}
	//複寫hashCOde()方法
	@Override
	public int hashCode(){
		return 13*description.hashCode()+17*partNumber;
	}
	//複寫compareTo方法
	@Override
	public int compareTo(Item other){
		return partNumber - other.partNumber;
	}
}	

c、TreeSet的小練習(自定義比較器)
import java.util.*;
/*
	按照字符串長度排序
	分析:字符串本身具有比較性,但不符合題目的需求,所以需要重寫一個比較器。
*/
public class TreeSetTest4{
	public static void main(String[] args){
		TreeSet<String> set = new TreeSet<>(new strLenComparetor());
		
		set.add("dadadwd");
		set.add("dasd");
		set.add("dsd");
		set.add("ddsdsdwd");
		set.add("daddsdswedcs");
		set.add("dsddd");
		set.add("da");
		
		Iterator<String> it = set.iterator();
		
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}

class strLenComparetor implements Comparator{
	public int compare(Object o1,Object o2){
		//將Object型強轉爲String型
		String s1 = (String)o1;
		String s2 = (String)o2;
		//比較
		int num =  new Integer(s1.length()).compareTo(new Integer(s2.length()));
		//當比較結果爲0時,將再次進行比較,以保證比較的準確性
		if(num == 0)
			s1.compareTo(s2);
		//不爲0時,返回num的值
		return num;
	}
}

d、TreeSet實現兩種比較方式的應用實例二:
import java.util.*;
public class TreeSetTest3{
	public static void main(String[] args){
		TreeSet<Student> set = new TreeSet<>(new MyCompare());
		set.add(new Student("zhangsan",25));
		set.add(new Student("lisi",23));
		set.add(new Student("wangwu",30));
		set.add(new Student("zhaoliu",19));
		set.add(new Student("zhaoliu2",19));
		set.add(new Student("zhuqi",28));
		set.add(new Student("zhuqi2",28));
		
		Iterator<Student> it = set.iterator();
		
		while(it.hasNext()){
			Student stu = it.next();
			System.out.println(stu.getName()+"........"+stu.getAge());
		}
	}
}
//自定義比較器
class MyCompare implements Comparator{
	public int compare(Object o1,Object o2){
		Student s1 = (Student)o1;
		Student s2 = (Student)o2;
		int num = s1.getName().compareTo(s2.getName());
		if(num == 0)
			return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		return num;
	}
}
//繼承Compareable,讓其具有比較性
class Student implements Comparable{
	private String name;
	private int age;
	
	public Student(String name,int age){
		this.name = name;
		this.age = age;
	}
	@Override
	public int compareTo(Object obj){
		//健壯性判斷
		if(obj == null) return -1;
		if(obj == this) return 0;
		if(!(obj instanceof Student)) 
			throw  new RuntimeException("類型不一致");
		Student s = (Student)obj;
		System.out.println(this.name+"......compareTo...."+s.name);
		if(this.age>s.age) return 1;
		if(this.age==s.age) {
			this.name.compareTo(s.name);
		}
		return -1;
	}
	
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
}


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