Java基礎知識——HashSet_TreeSet_Comparator

一、Set

(一)set概述(摘自API文檔)

 

public interface Set<E>
extends Collection<E>

set是一個不包含重複元素的 collection。更確切地講,set 不包含滿足 e1.equals(e2) 的元素對 e1 和 e2,並且最多包含一個 null 元素。正如其名稱所暗示的,此接口模仿了數學上的 set 抽象。

在所有構造方法以及 addequals 和 hashCode 方法的協定上,Set 接口還加入了其他規定,這些規定超出了從Collection 接口所繼承的內容。出於方便考慮,它還包括了其他繼承方法的聲明(這些聲明的規範已經專門針對Set 接口進行了修改,但是沒有包含任何其他的規定)。

對這些構造方法的其他規定是(不要奇怪),所有構造方法必須創建一個不包含重複元素的 set(正如上面所定義的)。

注:如果將可變對象用作 set 元素,那麼必須極其小心。如果對象是 set 中某個元素,以一種影響 equals 比較的方式改變對象的值,那麼 set 的行爲就是不確定的。此項禁止的一個特殊情況是不允許某個 set 包含其自身作爲元素。

(二)set集合通用方法

boolean

add(E e) 
          如果 set 中尚未存在指定的元素,則添加此元素(可選操作)。

boolean

addAll(Collection<? extends E> c) 
          如果 set 中沒有指定 collection 中的所有元素,則將其添加到此 set 中(可選操作)。

void

clear() 
          移除此 set 中的所有元素(可選操作)。

boolean

contains(Object o) 
          如果 set 包含指定的元素,則返回 true。

boolean

containsAll(Collection<?> c) 
          如果此 set 包含指定 collection 的所有元素,則返回 true。

boolean

equals(Object o) 
          比較指定對象與此 set 的相等性。

 int

hashCode() 
          返回 set 的哈希碼值。

boolean

isEmpty() 
          如果 set 不包含元素,則返回 true。

Iterator<E>

iterator() 
          返回在此 set 中的元素上進行迭代的迭代器。

boolean

remove(Object o) 
          如果 set 中存在指定的元素,則將其移除(可選操作)。

 boolean

removeAll(Collection<?> c) 
          移除 set 中那些包含在指定 collection 中的元素(可選操作)。

 boolean

retainAll(Collection<?> c) 
          僅保留 set 中那些包含在指定 collection 中的元素(可選操作)。

 int

size() 
          返回 set 中的元素數(其容量)。

 Object[]

toArray() 
          返回一個包含 set 中所有元素的數組。

<T> T[]

toArray(T[] a) 
          返回一個包含此 set 中所有元素的數組;返回數組的運行時類型是指定數組的類型。

 

 

二、     HashSet:

1)概述

此類實現 Set 接口,由哈希表(實際上是一個 HashMap 實例)支持。它不保證 set 的迭代順序;特別是它不保證該順序恆久不變。此類允許使用 null 元素。

注意,此實現不是同步的。如果多個線程同時訪問一個哈希 set,而其中至少一個線程修改了該 set,那麼它必須 保持外部同步。這通常是通過對自然封裝該 set 的對象執行同步操作來完成的。如果不存在這樣的對象,則應該使用 Collections.synchronizedSet 方法來“包裝” set。最好在創建時完成這一操作,以防止對該 set 進行意外的不同步訪問:

   Set s = Collections.synchronizedSet(new HashSet(...));

 

 

|--Set:元素是無序(存入和取出的順序不一定一致),元素不可以重複。、

       |--HashSet:底層數據結構是哈希表。是線程不安全的。不同步

                    

(2)HashSet是如何保證元素唯一性的呢?

是通過元素的兩個方法,hashCode和equals來完成。

如果元素的HashCode值相同,纔會判斷equals是否爲true。

如果元素的hashcode值不同,不會調用equals。

 

注意:對於判斷元素是否存在,以及刪除等操作,依賴的方法是元素的hashcode和equals方法。

 

Set集合的功能和Collection是一致的。

 

(3)自練

importjava.util.*;
/*
 
用HashSet存儲自定義對象
 
*/
 
class HashSetDemo
{
       public static void main(String[] args)
       {
              Set<Person> hs= newHashSet<Person>();
 
              hs.add(newPerson("zhangsan",20));
              hs.add(newPerson("zhangsan3",23));
              hs.add(newPerson("zhangsan2",22));
              hs.add(newPerson("zhangsan6",26));
              hs.add(newPerson("zhangsan2",22));//重複元素無法放入集合內
 
              sop(hs);
 
              Person p1 = newPerson("zhangsan6",26);
 
              sop(hs.contains(p1));//判斷對象是否存在
 
              sop(hs.remove(p1));//刪除對象
 
              sop(hs);
             
       }
 
       public static void sop(Object obj)
       {
              System.out.println(obj);
       }
}
 
 
class Person
{
       private String name;
       private int age;
 
       Person(String name,int age)
       {
              this.name = name;
              this.age = age;
       }
 
       public boolean equals(Object obj)
       {
              if (!(obj instanceof Person))
              {
                     throw newClassCastException("不是Person類");
              }
 
              Person p = (Person)obj;
 
              return this.name.equals(p.name)&& this.age == age;
       }
 
       public int hashCode()
       {
              returnthis.name.hashCode()+age*39;
       }
 
       public String toString()
       {
              returnthis.name+"_"+this.age;
       }
}
 


 

三、     TreeSet

 

(1)  概述

 

基於 TreeMap 的 NavigableSet 實現。使用元素的自然順序對元素進行排序,或者根據創建 set 時提供的Comparator 進行排序,具體取決於使用的構造方法。

此實現爲基本操作(addremove 和 contains)提供受保證的 log(n) 時間開銷。

注意,如果要正確實現 Set 接口,則 set 維護的順序(無論是否提供了顯式比較器)必須與 equals 一致。(關於與 equals 一致 的精確定義,請參閱 Comparable 或 Comparator。)這是因爲 Set 接口是按照 equals 操作定義的,但 TreeSet 實例使用它的 compareTo(或 compare)方法對所有元素進行比較,因此從 set 的觀點來看,此方法認爲相等的兩個元素就是相等的。即使 set 的順序與 equals 不一致,其行爲也 定義良好的;它只是違背了 Set 接口的常規協定。

注意,此實現不是同步的。

|--TreeSet:可以對Set集合中的元素進行排序。

                            底層數據結構是二叉樹。

保證元素唯一性的依據:compareTo方法return 0.

(2)TreeSet排序

TreeSet排序的第一種方式:讓元素自身具備比較性。元素需要實現Comparable接口,覆蓋compareTo方法。也種方式也成爲元素的自然順序,或者叫做默認順序。

TreeSet的第二種排序方式:當元素自身不具備比較性時,或者具備的比較性不是所需要的。這時就需要讓集合自身具備比較性。在集合初始化時,就有了比較方式。

 

(3)構造方法

構造方法摘要

TreeSet() 
          構造一個新的空 set,該 set 根據其元素的自然順序進行排序。

 

TreeSet(Collection<? extends E> c) 
          構造一個包含指定 collection 元素的新 TreeSet,它按照其元素的自然順序進行排序。

 

TreeSet(Comparator<? super E> comparator) 
          構造一個新的空 TreeSet,它根據指定比較器進行排序。

 

TreeSet(SortedSet<E> s) 
          構造一個與指定有序 set 具有相同映射關係和相同排序的新 TreeSet。

 

 

(4)自練

 

import java.util.*;
 
/*
 
需求:在TreeSet中存儲學生類的自定義對象
學生類中有姓名和年齡,首先按照姓名排序,若姓名相同,則按照年齡排序
 
*/
 
class TreeSetDemo
{
       publicstatic void main(String[] args)
       {
              Set<Student>ts = new TreeSet<Student>();
 
              ts.add(newStudent("Dabao",28));
              ts.add(newStudent("Sibao",25));                           
              ts.add(newStudent("Sanbao",26));
              ts.add(newStudent("Sibao",24));
              ts.add(newStudent("Erbao",27));
             
              Iterator<Student>it = ts.iterator();
 
              while(it.hasNext())
              {
                     sop(it.next());
              }
 
       }
 
       publicstatic void sop(Object obj)
       {
              System.out.println(obj);
       }
}
 
class Student implements Comparable//此接口強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序
{
       privateString name;
       privateint age;
 
       Student(Stringname,int age)
       {
              this.name= name;
              this.age= age;
       }
 
       publicString getName()
       {
              returnthis.name;
       }
 
       public intgetAge()
       {
              returnthis.age;
       }
 
       public intcompareTo(Object obj)//compareTo 方法被稱爲它的自然比較方法
       {
              if(!(obj instanceof Student))//比較之前要先判斷類型是否匹配
              {
                     thrownew ClassCastException("不是學生類");
              }
             
              Studentstu = (Student)obj;
 
              intnum = (this.name).compareTo(stu.getName());//將比較結果存入變量中待返回
 
              if(num==0)  //如果姓名相同,則判斷年齡
              {
                     returnstu.getAge()-this.age;
              }
              returnnum;
       }
 
       publicString toString()
       {
              returnname+"_"+age;
       }
}
 
 

四、比較器Comparator

 

強行對某個對象 collection 進行整體排序 的比較函數。可以將Comparator 傳遞給 sort 方法(如Collections.sort 或 Arrays.sort),從而允許在排序順序上實現精確控制。還可以使用Comparator 來控制某些數據結構(如有序 set有序映射)的順序,或者爲那些沒有自然順序的對象 collection 提供排序。

 

自練

import java.util.*;
/*
 
需求:使用比較器對TreeSet進行排序
 
*/
 
class CompDemo
{
       publicstatic void main(String[] args)
       {
              Set<Student>ts = new TreeSet<Student>();
 
              ts.add(newStudent("Dabao",28));
              ts.add(newStudent("Sibao",25));                       
              ts.add(newStudent("Sanbao",26));
              ts.add(newStudent("Sibao",24));
              ts.add(newStudent("Erbao",27));
             
              Iterator<Student>it = ts.iterator();
 
              while(it.hasNext())
              {
                     sop(it.next());
              }
      
       }
 
       publicstatic void sop(Object obj)
       {
              System.out.println(obj);
       }
}
 
class MyComparator implements Comparator  //比較器接口,實現該接口需要重寫compare()方法
{
       publicint compare(Object o1, Object o2)//這次按照年齡排序
       {
              if(!(o1 instanceof Student && o2 instanceof Student))
              {
                     thrownew ClassCastException("不是學生類");
              }
 
              Students1 = (Student)o1;
              Students2 = (Student)o2;
 
              intnum = ((Integer)s1.getAge()).compareTo((Integer)s2.getAge());
              if(num == 0)
              {
                     returns1.getName().compareTo(s2.getName());
              }
              returnnum;
       }
 
}
/*
 
繼續用上個例子中的學生類,當類既有自然順序,又有比較器時,使用比較器排序
 
*/
 
class Student implements Comparable//此接口強行對實現它的每個類的對象進行整體排序。這種排序被稱爲類的自然排序
{
       privateString name;
       privateint age;
 
       Student(Stringname,int age)
       {
              this.name= name;
              this.age= age;
       }
 
       publicString getName()
       {
              returnthis.name;
       }
 
       publicint getAge()
       {
              returnthis.age;
       }
 
       publicint compareTo(Object obj)//compareTo 方法被稱爲它的自然比較方法
       {
              if(!(obj instanceof Student))//比較之前要先判斷類型是否匹配
              {
                     thrownew ClassCastException("不是學生類");
              }
             
              Studentstu = (Student)obj;
 
              intnum = (this.name).compareTo(stu.getName());//將比較結果存入變量中待返回
 
              if(num==0)  //如果姓名相同,則判斷年齡
              {
                     returnstu.getAge()-this.age;
              }
              returnnum;
       }
 
       publicString toString()
       {
              returnname+"_"+age;
       }
}
 

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