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。
並且通常這些常用的容器都是不同步的。