天天看點

JDK1.9-Set接口

java.util.Set

接口和 java.util.List 接口一樣,同樣繼承自 Collection 接口,它與 Collection 接口中的方 法基本一緻,并沒有對 Collection 接口進行功能上的擴充,隻是比 Collection 接口更加嚴格了。與 List 接口不 同的是, Set 接口中元素無序,并且都會以某種規則保證存入的元素不出現重複。

Set 集合有多個子類,這裡我們介紹其中的

java.util.HashSet

java.util.LinkedHashSet

這兩個集合。

tips:Set集合取出元素的方式可以采用:疊代器、增強for。
3.1 HashSet集合介紹

java.util.HashSet

是 Set 接口的一個實作類,它所存儲的元素是不可重複的,并且元素都是無序的(即存取順序 不一緻)。

java.util.HashSet

底層的實作其實是一個

java.util.HashMap

支援,由于我們暫時還未學習,先做了解。

HashSet 是根據對象的哈希值來确定元素在集合中的存儲位置,是以具有良好的存取和查找性能。保證元素唯一性 的方式依賴于: hashCode 與 equals 方法。

我們先來使用一下Set集合存儲,看下現象,再進行原理的講解:

public class HashSetDemo {
    public static void main(String[] args) {
        //建立 Set集合
        HashSet<String> set = new HashSet<String>(); 
        //添加元素 
        set.add(new String("cba")); 
        set.add("abc"); 
        set.add("bac"); 
        set.add("cba"); 
        // 周遊 
        for (String name : set) {
            System.out.println(name);
        }
    }
}
           

輸出結果如下,說明集合中不能存儲重複元素:

cba 
abc 
bac
           
tips:根據結果我們發現字元串"cba"隻存儲了一個,也就是說重複的元素set集合不存儲。
2.2 HashSet集合存儲資料的結構(哈希表)

什麼是哈希表呢?

在JDK1.8之前,哈希表底層采用數組+連結清單實作,即使用連結清單處理沖突,同一hash值的連結清單都存儲在一個連結清單裡。 但是當位于一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低。而JDK1.8中,哈 希表存儲采用數組+連結清單+紅黑樹實作,當連結清單長度超過門檻值(8)時,将連結清單轉換為紅黑樹,這樣大大減少了查找 時間。

JDK1.9-Set接口

看到這張圖就有人要問了,這個是怎麼存儲的呢?

為了友善大家的了解我們結合一個存儲流程圖來說明一下:

JDK1.9-Set接口

總而言之,JDK1.8引入紅黑樹大程度優化了HashMap的性能,那麼對于我們來講保證HashSet集合元素的唯一, 其實就是根據對象的hashCode和equals方法來決定的。如果我們往集合中存放自定義的對象,那麼保證其唯一, 就必須複寫hashCode和equals方法建立屬于目前對象的比較方式。

2.3 HashSet存儲自定義類型元素

給HashSet中存放自定義類型元素時,需要重寫對象中的hashCode和equals方法,建立自己的比較方式,才能保 證HashSet集合中的對象唯一

建立自定義Student類

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
           
public class HashSetDemo2 {
    public static void main(String[] args) {
        //建立集合對象 該集合中存儲 Student類型對象 
         HashSet<Student> stuSet = new HashSet<Student>(); 
         //存儲 
         Student stu = new Student("于謙", 43); 
         stuSet.add(stu); 
         stuSet.add(new Student("郭德綱", 44)); 
         stuSet.add(new Student("于謙", 43)); 
         stuSet.add(new Student("郭麒麟", 23)); 
         stuSet.add(stu); 
        for (Student stu2 : stuSet) {
            System.out.println(stu2);
        }
    }
}
           

執行結果

執行結果: 
Student [name=郭德綱, age=44] 
Student [name=于謙, age=43] 
Student [name=郭麒麟, age=23]
           
2.3 LinkedHashSet

我們知道HashSet保證元素唯一,可是元素存放進去是沒有順序的,那麼我們要保證有序,怎麼辦呢? 在HashSet下面有一個子類

java.util.LinkedHashSet

,它是連結清單和哈希表組合的一個資料存儲結構。 示範代碼如下:

JDK1.9-Set接口
2.4 可變參數

在JDK1.5之後,如果我們定義一個方法需要接受多個參數,并且多個參數類型一緻,我們可以對其簡化成如下格式:

修飾符 傳回值類型 方法名(參數類型... 形參名){ }
           

其實這個書寫完全等價與

修飾符 傳回值類型 方法名(參數類型[] 形參名){ }
           

隻是後面這種定義,在調用時必須傳遞數組,而前者可以直接傳遞資料即可。

JDK1.5以後。出現了簡化操作。… 用在參數上,稱之為可變參數。

同樣是代表數組,但是在調用這個帶有可變參數的方法時,不用建立數組(這就是簡單之處),直接将數組中的元素 作為實際參數進行傳遞,其實編譯成的class檔案,将這些元素先封裝到一個數組中,在進行傳遞。這些動作都在編 譯.class檔案時,自動完成了。