天天看點

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

      一Set接口

      Set接口可以與數學中的集合的概念相對應。Set接口是Collection接口的子接口,Set接口裡多個對象之間沒有明

顯的順序。具體詳細方法請參考API文檔(可見身邊随時帶上API文檔有多重要),基本與Collection接口中定義的方法相

同。隻是行為不同(Set不允許包含重複元素)。

      Set集合不允許重複元素,是因為Set判斷兩個對象相同不是使用==運算符,而是根據equals()方法。即兩個對象

用equals()方法比較傳回true,Set就不能接受兩個相等的對象。

      我們來做個測試:

import java.util.*;

public class TestSet{  
    public static void main(String[] args){  
        Set<String> books = new HashSet<String>();  
          
        //添加一個字元串對象  
        books.add(new String("我是測試的對象"));  
          
        //再次添加一個字元串對象,  
        //因為兩個字元串對象通過equals方法比較相等,是以添加失敗,傳回false  
        boolean result = books.add(new String("我是測試的對象"));  
          
        System.out.println(result);  
          
        //下面輸出看到集合隻有一個元素  
        System.out.println(books);    
    }  
} 
           

      運作結果:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

      說明:程式中,book集合兩次添加的字元串對象明顯不是一個對象(程式通過new關鍵字來建立字元串對象),

當使用==運算符判斷傳回false,使用equals方法比較傳回true,是以不能添加到Set集合中,最後隻能輸出一個元

素。

      Set接口中定義的方法:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet
JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

      Set接口中的知識,同時也适用于HashSet、TreeSet等實作類。J2SDK API中所提供的Set接口實作類有

HashSet、TreeSet等,下面我們進行逐一介紹。

       二實作類HashSet

       HashSet(哈希集),是Set接口的一個重要實作類。HashSet使用的是相當複雜的方式來存儲元素的,使用

HashSet能夠最快的擷取集合中的元素,效率非常高(以空間換時間)。會根據hashcode()方法和equals()方法來判

斷是否是同一個對象,如果hashcode()方法一樣,并且equals()方法傳回true,則是同一個對象,不能重複存放。

       HashSet實作類中定義的方法:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

       HashSet按Hash算法來存儲集合的元素,是以具有很好的存取和查找性能。

       HashSet的特點:

       (1)HashSet不是同步的,多個線程通路是需要通過代碼保證同步。

       (2)集合元素值可以使null。

       (3)HashSet集合判斷兩個元素相等的标準是兩個對象通過equals()方法比較相等,并且兩個對象的hashCode()方

法傳回值也相等。

       執行個體代碼:

import java.util.*;

public class TestHashSet  {  
    public static void main(String[] args){  
        Set<Object> books = new HashSet<Object>();  
        //分别向books集合中添加2個A對象,2個B對象,2個C對象  
        books.add(new A());  
        books.add(new A());  
        books.add(new B());  
        books.add(new B());  
        books.add(new C());  
        books.add(new C());  
        System.out.println(books);  
    }  
} 

//類A的equals方法總是傳回true,但沒有重寫其hashCode()方法  
class A{  
    public boolean equals(Object obj)  {  
        return true;  
    }  
}  

//類B的hashCode()方法總是傳回1,但沒有重寫其equals()方法  
class B{  
    public int hashCode(){  
        return 1;  
    }  
}  

//類C的hashCode()方法總是傳回2,但沒有重寫其equals()方法  
class C{  
    public int hashCode(){  
        return 2;  
    }  

    public boolean equals(Object obj){  
        return true;  
    }  
}  
           

       運作結果:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

       說明:

       (1)Object類提供的toString()方法總是傳回該對象實作類的類名+@+hashCode(16進制數)值,是以可以看到上面

程式輸出的結果。可以通過重寫toString()方法來輸出自己希望的形式。

      (2)即使2個A對象通過equals()比較傳回true,但HashSet依然把它們當成2個對象;即使2個B對象的hashCode()返

回相同值,但HashSet依然把它們當成2個對象。即如果把一個對象放入HashSet中時,如果重寫該對象equals()方

法,也應該重寫其hashCode()方法。其規則是:如果2個對象通過equals方法比較傳回true時,這兩個對象的

hashCode也應該相同。

       知道了上面的方法,我們再來看看下面的執行個體:

import java.util.*;

public class TestHashSet {
    public static void main(String[] args) {
        Set<Student> set = new HashSet<Student>();
        //添加兩個相同的對象
        Student s1 = new Student(1);
        Student s2 = new Student(1);
        Student s3 = new Student(2);
        set.add(s1);
        set.add(s2);
        set.add(s3);
	//周遊set中的對象
        for (Student s : set) {
            System.out.println(s);
        }
    }
}

class Student{
    int id;

    public Student(int id) {
        this.id = id;
    }
	
    @Override
    public String toString() {
        return this.id+"";
    }
	
    @Override
    public int hashCode() {
        return this.id;
    }
	
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Student){
            Student  stu = (Student) obj;
            if (stu.id == this.id)
                return true;
        }
        return false;
    }
}
           

       運作結果:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

        正如上例所示,重寫了hashCode()和equals()方法來區分同意對象後,就不能存放同以對象了。如果注釋這兩個

方法,則所有Student對象視為不同對象,都可以存放。

        三實作類TreeSet

        TreeSet也不能存放重複對象,但是TreeSet會自動排序,如果存放的對象不能排序則會報錯,是以存放的對象

必須指定排序規則。

       TreeSet實作類定義的方法:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet
JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

       排序規則包括自然排序和客戶排序。

  (1)自然排序:TreeSet要添加哪個對象就在哪個對象類上面實作java.lang.Comparable接口,并且重寫

comparaTo()方法,傳回0則表示是同一個對象,否則為不同對象。

       (2)客戶排序:建立一個第三方類并實作java.util.Comparator接口。并重寫方法。定義集合形式為TreeSet ts =

 new TreeSet(new 第三方類());

      下面一個例子用TreeSet存放自然排序的對象:

import java.util.*;

public class TestTreeSet {
    public static void main(String[] args) {
        Set<Student1> set = new TreeSet<Student1>();
        Student1 s1 = new Student1(5);
        Student1 s2 = new Student1(1);
        Student1 s3 = new Student1(2);
        Student1 s4 = new Student1(4);
        Student1 s5 = new Student1(3);
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        for (Student1 s : set) {
            System.out.println(s);
        }
    }
}

class Student1 implements Comparable<Student1>{
    int id;

    public Student1(int id) {
        this.id = id;
    }
	
    @Override
    public String toString() {
        return this.id+"";
    }
	
    @Override
    public int hashCode() {
        return this.id;
    }
	
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Student1){
            Student1  stu = (Student1) obj;
            if (stu.id == this.id)
                return true;
        }
        return false;
    }
	
    public int compareTo(Student1 o) {
        return (this.id-o.id);
    }
}
           

        運作結果:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

       下面一個例子用TreeSet存放客戶排序的對象:

import java.util.*;

public class TestTreeSet2 {
    public static void main(String[] args) {
        Set<Student2> set = new TreeSet<Student2>(new MySort());
        Student2 s1 = new Student2(5);
        Student2 s2 = new Student2(1);
        Student2 s3 = new Student2(2);
        Student2 s4 = new Student2(4);
        Student2 s5 = new Student2(3);
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        for (Student2 s : set) {
            System.out.println(s);
        }
    }
}

class MySort implements java.util.Comparator<Student2>{
    public int compare(Student2 o1, Student2 o2) {
        return o2.id-o1.id;
    }
}

class Student2{
    int id;

    public Student2(int id) {
        this.id = id;
    }
	
    @Override
    public String toString() {
        return this.id+"";
    }
	
    @Override
    public int hashCode() {
        return this.id;
    }
	
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Student2){
            Student2  stu = (Student2) obj;
            if (stu.id == this.id)
                return true;
        }
        return false;
    }
}
           

       運作結果:

JavaSE入門學習36:Java集合架構之Set接口及其實作類HashSet和TreeSet      一Set接口       二實作類HashSet        三實作類TreeSet

       說明:由運作結果可以看出,TreeSet并不是根據元素的插入順序進行排序,而是根據元素實際值來進行排序。

TreeSet采用紅黑樹的資料結構對元素進行排序,具體排序内容會在後續文章中說明。