1. 程式人生 > >JAVA常用集合框架用法詳解基礎篇三之Colletion子介面Set

JAVA常用集合框架用法詳解基礎篇三之Colletion子介面Set

這一篇我們來介紹Collection介面的另一個子介面,Set介面。Set是個介面,元素不可以重複,是無序的。Set介面中的方法和Collection的一致。

A、Set的子類:

1、HashSet:此類實現的Set介面,由雜湊表(實際上是一個HashMap)例項支援,它不保證Set的迭代順序,但是允許使用null元素。內部結構是雜湊表,是不同步的。

雜湊表確定元素是否相同的步驟如下:

一、    判斷的是兩個元素的雜湊值(hashcode)是否相同。如果相同,再判斷兩個物件的內容是否相同,如果內容相同就表示兩個元素是相同的。

二、    判斷雜湊值是否相同,其實判斷的是物件的hashCode()的方法。判斷內容是否相同,用的是equals()方法。

三、    如果雜湊值不同,那就不需要進行equals判斷。

HashSet集合資料結構是雜湊表,所以儲存元素的時候,使用元素的hashCode()方法來確定位置,如果位置相同,再通過元素的equals方法來確定是否相同。

 

練習題:定義功能去除ArrayList的重複元素?

注意:像ArrayList集合,在判斷元素是否相同的時候,僅僅需要判斷equals()方法。因為資料結構不同,對元素的判斷依據也就一樣。

程式碼如下:

package com.wq.person;

public class Person extends Object {
		private String name;
		private int age;
		
		public Person() {
			super();
			// TODO Auto-generated constructor stub
		}
		public Person(String name, int age) {
			super();
			this.name = name;
			this.age = age;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public int getAge() {
			return age;
		}
		public void setAge(int age) {
			this.age = age;
		}
	
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + age;
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (!(obj instanceof Person))
				return false;
			Person other = (Person) obj;
			if (age != other.age)
				return false;
			if (name == null) {
				if (other.name != null)
					return false;
			} else if (!name.equals(other.name))
				return false;
			return true;
		}
		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return name+"...."+age;
		}
		
}





//hashset測試程式
package com.wq.hashset;

import java.util.HashSet;
import java.util.Iterator;

import com.wq.person.Person;

public class testHashSet {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet hs=new HashSet();//例項化一個hashset物件
		hs.add(new Person("lisi1",21));
		hs.add(new Person("lisi2",22));
		hs.add(new Person("lisi3",23));
		hs.add(new Person("lisi4",24));
		hs.add(new Person("lisi4",24));//如果想在迭代中不出現相同的元素,需要通過覆寫Person類的hashcode和equals方法
		//使用迭代器進行迭代
		
		for(Iterator it=hs.iterator();it.hasNext();){
			Person pe=(Person)it.next();
			System.out.println(pe.getName()+"---"+pe.getAge());
		}
	}

}


執行結果如下(由於無序這只是一種可能):
lisi4---24
lisi3---23
lisi2---22
lisi1---21

特別注意:如果希望元素不重複,但是要有序,這時可以考慮使用LinkedHashSet,它是HashSet的子介面。


 2、TreeSet介面,可以對Set集合的元素進行排序,不是同步的。它底層的資料結構是紅黑樹。

判斷元素唯一性的方式就是根據比較方法compareTo()的返回結果,判斷返回的結果是否為0,是0就表示相同的元素且不會儲存在Set中的(Set是不允許儲存重複的元素的)。如果返回的結果不是0,則表示的是不相同。

TreeSet對元素進行排序的方式一:讓元素具備比較功能,元素需要實現comparable介面,覆蓋CompareTo()方法。

 

如果不要按照物件具備的自然順序進行排序,如果物件不具備自然順序。(即物件沒有比較性,或者具備的比較性不是我們所需要的)這個時候怎麼辦???

TreeSet對元素進行排序的方式二:(生成一個比較器)讓集合自身具備比較的功能,定義一個類,實現Comparator介面,覆蓋compare方法,將該類的物件作為引數傳遞給TreeSet集合的建構函式。

   

程式碼演示如下:

//Person類
package com.wq.person;
//需要實現Comparable介面
public class Person extends Object implements Comparable{
		private String name;
		private int age;
		
		public Person() {
			super();
			// TODO Auto-generated constructor stub
		}
		public Person(String name, int age) {
			super();
			this.name = name;
			this.age = age;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public int getAge() {
			return age;
		}
		public void setAge(int age) {
			this.age = age;
		}
	
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + age;
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (!(obj instanceof Person))
				return false;
			Person other = (Person) obj;
			if (age != other.age)
				return false;
			if (name == null) {
				if (other.name != null)
					return false;
			} else if (!name.equals(other.name))
				return false;
			return true;
		}
		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return name+"...."+age;
		}
		//需要覆寫的compareTo方法
		//這裡我的思路是先比較age的大小,如果age相等,則
		//接著比較name的字典順序大小
		@Override
		public int compareTo(Object o) {
			// TODO Auto-generated method stub
			Person per=(Person) o;//實現強制型別轉換
			if(this.age>per.age){
				return 1;
			}else if(this.age<per.age){
				return -1;
			}else{//如果年紀相等就比較名字的字典順序大小
				int temp=this.name.compareTo(per.name);
				return temp;
			}
			
			
		}
		
}


//自己寫的Comparator介面
package com.wq.comparator;

import java.util.Comparator;

import com.wq.person.Person;

public class ComparatorByName implements Comparator {

	/**
	 * 覆寫compare方法,生成一個比較器。這裡我們用name來作為比較
	 */
	@Override
	public int compare(Object o1, Object o2) {
		// TODO Auto-generated method stub
		Person p1=(Person)o1;
		Person p2=(Person)o2;
		
		int temp=p1.getName().compareTo(p2.getName());//獲取兩個物件的name比較的結果
		return temp==0?p1.getAge()-p2.getAge():temp;
	}

}


//測試類。用於測試CompareTo()方法和Comparable介面
package com.wq.TreeSet;

import java.util.Iterator;
import java.util.TreeSet;

import com.wq.comparator.ComparatorByName;
import com.wq.person.Person;

public class testTreeSet {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//測試實現Comparable介面的比較功能
		System.out.println("測試實現Comparable介面的比較功能");
		testComparableDemo();
		
		System.out.println("測試實現Comparator介面,作為一個比較器來進行比較的功能");
		//測試實現Comparator介面,作為一個比較器來進行比較的功能
		testComparatorDemo();
		
	}

	public static void testComparatorDemo() {
		TreeSet ts=new TreeSet(new ComparatorByName());//例項化物件,並且確定比較器
		//新增自定義物件
		//在新增元素時,自定義的物件必須實現Comparator介面,同時要覆蓋compare方法
		//否則就會報錯
		ts.add(new Person("zhangsan",22));
		ts.add(new Person("zhaoliu",24));
		ts.add(new Person("zhouqi",25));
		ts.add(new Person("wuba",28));
		ts.add(new Person("lisi",26));
		ts.add(new Person("wangwu",25));
		
		for(Iterator it=ts.iterator();it.hasNext();){
			Person per=(Person)it.next();
			System.out.println(per);
		}
	}

	public static void testComparableDemo() {
		TreeSet ts=new TreeSet();//例項化物件,
		//新增自定義物件
		//在新增元素時,自定義的物件必須實現Comparable介面,同時要覆蓋compareTo方法
		//否則就會報錯
		ts.add(new Person("zhangsan",22));
		ts.add(new Person("zhaoliu",24));
		ts.add(new Person("zhouqi",25));
		ts.add(new Person("wuba",28));
		ts.add(new Person("lisi",26));
		ts.add(new Person("wangwu",25));
		
		for(Iterator it=ts.iterator();it.hasNext();){
			Person per=(Person)it.next();
			System.out.println(per);
		}
	}

}

執行結果如下:

測試實現Comparable介面的比較功能(以年齡大小)

zhangsan....22

zhaoliu....24

wangwu....25

zhouqi....25

lisi....26

wuba....28

測試實現Comparator介面,作為一個比較器來進行比較的功能(以名字的字典順序)

lisi....26

wangwu....25

wuba....28

zhangsan....22

zhaoliu....24

zhouqi....25


練習:TreeSet集合練習,字串長度的排序

    分析:Java程式碼中。TreeSet預設的會為字串進行字典順序大小的排序,但這不符合我們的要求。這個時候怎麼辦,我們必須要用到比較器。即comparator介面來實現。

具體程式碼實現如下:

//自定義的比較器
package com.wq.comparator;

import java.util.Comparator;

import com.wq.person.Person;
/*
 * 生成一個比較器,用來比較字串的長度大小,如果長度相等則比較字元的字典順序大小
 */
public class ComparatorByLength implements Comparator {

	@Override
	public int compare(Object o1, Object o2) {
		// TODO Auto-generated method stub
		String str1=(String)o1;
		String str2=(String)o2;
		int temp=str1.length()-str2.length();
		return temp==0?str1.compareTo(str2):temp;
	}

}

//測試類
package com.wq.TreeSet;

import java.util.Iterator;
import java.util.TreeSet;

import com.wq.comparator.ComparatorByLength;
import com.wq.person.Person;

/**
 * 這個練習是對TreeSet集合的練習
 * 主要是進行字串的長度的排序
 * @author LULEI
 *
 */
public class testTreeSetDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TreeSet ts=new TreeSet(new ComparatorByLength());//在建構函式中新增相應的構造器
		
		ts.add("asdfdf");
		ts.add("dds");
		ts.add("fghf");
		ts.add("as");
		ts.add("t");
		ts.add("fdsfsg");
		
		for(Iterator it=ts.iterator();it.hasNext();){
			Object o=(Object)it.next();
			System.out.println(o);
		}
	}

}

執行結果如下:

t

as

dds

fghf

asdfdf

fdsfsg

--------------------------------------------------------------------*--------------------------------------------------------------------------------------------------

我們已經介紹了List和Set介面,接下來總結一下。

總結:List:       1---ArrayList     2---LinkedList

            Set         1---HashSet    --LinkedHashSet

                           2---TreeSet

注意,字尾名就是該集合所屬的體系,字首名就是該集合的資料結構。

    1、 看到array:就要想到陣列,就要想到查詢快,有角標。如果不希望出現重複的元素則需要覆蓋equals()方法。

     2、看到link就要想到連結串列,就要想到增刪快,就要想到add/get/remove+first(last)的方法。

     3、看到hash就要想到雜湊表,就要想到唯一性,就要想到元素需要覆蓋hashCode()和equals()方法。

     4、看到tree就要想到二叉樹,就要想到排序,就要想到兩個介面:comparator和comparable。

 並且通常這些常用的容器都是不同步的。