java基礎------HashSet與LinkedHashSet介紹

Set接口

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

Set集合有多個子類,這裏我們介紹其中的java.util.HashSetjava.util.LinkedHashSet這兩個集合。

Set集合取出元素的方式可以採用:迭代器、增強for。

HashSet集合介紹

java.util.HashSetSet接口的一個實現類,它所存儲的元素是不可重複的,並且元素都是無序的(即存取順序不一致)。java.util.HashSet底層的實現其實是一個java.util.HashMap支持,瞭解。

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

我們先來使用一下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

根據結果我們發現字符串"cba"只存儲了一個,也就是說重複的元素set集合不存儲。

HashSet集合存儲數據的結構(哈希表)

什麼是哈希表呢?

JDK1.8之前,哈希表底層採用數組+鏈表實現,即使用鏈表處理衝突,同一hash值的鏈表都存儲在一個鏈表裏。但是當位於一個桶中的元素較多,即hash值相等的元素較多時,通過key值依次查找的效率較低。
JDK1.8中,哈希表存儲採用數組+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換爲紅黑樹,這樣大大減少了查找時間。

簡單的來說,哈希表是由數組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實現的,如下圖所示。
在這裏插入圖片描述

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

爲了方便大家的理解我們結合一個存儲流程圖來說明一下:
在這裏插入圖片描述

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

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]

由結果看出自定義的數據類型中,必須重寫hashcode,equals ,之後HashSet集合中的對象類型就不會有重複

LinkedHashSet

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

在HashSet下面有一個子類java.util.LinkedHashSet,它是鏈表和哈希表組合的一個數據存儲結構。

演示代碼如下:

package set集合;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

public class HashSet {
    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<String>();
        set.add("bbb");
        set.add("aaa");
        set.add("abc");
        set.add("bbc");
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
        System.out.println("--------------------------------");

        Set<String> set1 = new LinkedHashSet<String>();
        set1.add("aaa");
        set1.add("bbb");
        set1.add("ccc");
        set1.add("ddd");

        Iterator<String> it1 = set1.iterator();
        while (it1.hasNext()) {
            System.out.println(it1.next());
        }
    }
}
結果:
bbb
aaa
abc
bbc
--------------------------------
aaa
bbb
ccc
ddd

總結

Set接口的特點:
        1.不允許存儲重複的元素
        2.沒有索引,沒有帶索引的方法,也不能使用普通的for循環遍歷
        
java.util.HashSet集合 implements Set接口

HashSet特點:
         1.不允許存儲重複的元素
         2.沒有索引,沒有帶索引的方法,也不能使用普通的for循環遍歷
         3.是一個無序的集合,存儲元素和取出元素的順序有可能不一致
         4.底層是一個哈希表結構(查詢的速度非常的快)
         
LinkedHashSet集合特點:
        1.底層是一個哈希表(數組+鏈表/紅黑樹)+鏈表:多了一條鏈表(記錄元素的存儲順序),保證元素有序

在這裏插入圖片描述

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