Java Set集合及其子類HashSet與LinkedHashSet詳解
前言:
java.util.Set接口和 java.util.List接口一樣,同樣繼承自 Collection接口,它與 Collection接口中的方法基本一致,并沒有對 Collection接口進(jìn)行功能上的擴(kuò)充,只是比 Collection接口更加嚴(yán)格了。與 List接口不同的是, Set接口中元素?zé)o序,并且都會(huì)以某種規(guī)則保證存入的元素不出現(xiàn)重復(fù)。Set集合有多個(gè)子類,這里我們介紹其中的 java.util.HashSet、 java.util.LinkedHashSet這兩個(gè)集合。
tips:Set集合取出元素的方式可以采用:迭代器、增強(qiáng)for。
一、HashSet集合介紹
java.util.HashSet是Set接口的一個(gè)實(shí)現(xiàn)類,它所存儲(chǔ)的元素是不可重復(fù)的,并且元素都是無序的(即存取順序不一致)。java.util.HashSet底層的實(shí)現(xiàn)其實(shí)是一個(gè)java.util.HashMap支持。
HashSet是根據(jù)對象的哈希值來確定元素在集合中的存儲(chǔ)位置,因此具有良好的存取和查找性能。保證元素唯一性的方式依賴于:hashCode與equals方法。
我們先來使用一下Set集合存儲(chǔ),看下現(xiàn)象,再進(jìn)行原理的講解:
public class HashSetDemo {
public static void main(String[] args) {
//創(chuàng)建 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);
}
}
}輸出結(jié)果如下,說明集合中不能存儲(chǔ)重復(fù)元素:
cba
abc
bac
tips:根據(jù)結(jié)果我們發(fā)現(xiàn)字符串"cba"只存儲(chǔ)了一個(gè),也就是說重復(fù)的元素set集合不存儲(chǔ)。
二、HashSet集合存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu)(哈希表)
1.什么是哈希表呢?
在JDK1.8之前,哈希表底層采用數(shù)組+鏈表實(shí)現(xiàn),即使用鏈表處理沖突,同一hash值的鏈表都存儲(chǔ)在一個(gè)鏈表里。但是當(dāng)位于一個(gè)桶中的元素較多,即hash值相等的元素較多時(shí),通過key值依次查找的效率較低。而JDK1.8中,哈希表存儲(chǔ)采用數(shù)組+鏈表+紅黑樹實(shí)現(xiàn),當(dāng)鏈表長度超過閾值(8)時(shí),將鏈表轉(zhuǎn)換為紅黑樹,這樣大大減少了查找時(shí)間。
簡單的來說,哈希表是由數(shù)組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實(shí)現(xiàn)的,
如下圖所示:

看到這張圖就有人要問了,這個(gè)是怎么存儲(chǔ)的呢?
為了方便大家的理解我們結(jié)合一個(gè)存儲(chǔ)流程圖來說明一下:

總而言之,JDK1.8引入紅黑樹大程度優(yōu)化了HashMap的性能,那么對于我們來講保證HashSet集合元素的唯一,其實(shí)就是根據(jù)對象的hashCode和equals方法來決定的。如果我們往集合中存放自定義的對象,那么保證其唯一,就必須復(fù)寫hashCode和equals方法建立屬于當(dāng)前對象的比較方式。
三、HashSet存儲(chǔ)自定義類型元素
給HashSet中存放自定義類型元素時(shí),需要重寫對象中的hashCode和equals方法,建立自己的比較方式,才能保證HashSet集合中的對象唯一。
創(chuàng)建自定義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) {
//創(chuàng)建集合對象 該集合中存儲(chǔ) Student類型對象
HashSet<Student> stuSet = new HashSet<Student>();
//存儲(chǔ)
Student stu = new Student("張三", 43);
stuSet.add(stu);
stuSet.add(new Student("李四", 66));
stuSet.add(new Student("張三", 43));
stuSet.add(new Student("王五", 23));
stuSet.add(stu);
for (Student stu2 : stuSet) {
System.out.println(stu2);
}
}
}
執(zhí)行結(jié)果:
Student [name=李四, age=66]
Student [name=張三, age=43]
Student [name=王五, age=23]
四、LinkedHashSet
我們知道HashSet保證元素唯一,可是元素存放進(jìn)去是沒有順序的,那么我們要保證有序,怎么辦呢?
在HashSet下面有一個(gè)子類java.util.LinkedHashSet,它是鏈表和哈希表組合的一個(gè)數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)。
演示代碼如下:
public class LinkedHashSetDemo {
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());
}
}
}結(jié)果:
bbb
aaa
abc
bbc
到此這篇關(guān)于Java Set集合及其子類HashSet與LinkedHashSet詳解的文章就介紹到這了,更多相關(guān)Java Set集合 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡單了解mybatis攔截器實(shí)現(xiàn)原理及實(shí)例
這篇文章主要介紹了簡單了解mybatis攔截器實(shí)現(xiàn)原理及實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01
Spring boot集成Kafka消息中間件代碼實(shí)例
這篇文章主要介紹了Spring boot集成Kafka消息中間件代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
SpringBoot如何實(shí)現(xiàn)緩存預(yù)熱
緩存預(yù)熱是指在 Spring Boot 項(xiàng)目啟動(dòng)時(shí),預(yù)先將數(shù)據(jù)加載到緩存系統(tǒng)(如 Redis)中的一種機(jī)制,本文主要介紹了SpringBoot如何實(shí)現(xiàn)緩存預(yù)熱,感興趣的可以了解下2024-12-12
springboot日志文件名稱叫l(wèi)ogback-spring.xml的原因解析
這篇文章主要介紹了springboot日志文件名稱為什么叫l(wèi)ogback-spring.xml,本文給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
Spring Scheduling本地任務(wù)調(diào)度設(shè)計(jì)與實(shí)現(xiàn)方式
這篇文章主要介紹了Spring Scheduling本地任務(wù)調(diào)度設(shè)計(jì)與實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04

