Java Set集合及其子類(lèi)HashSet與LinkedHashSet詳解
前言:
java.util.Set
接口和 java.util.List
接口一樣,同樣繼承自 Collection
接口,它與 Collection
接口中的方法基本一致,并沒(méi)有對(duì) Collection
接口進(jìn)行功能上的擴(kuò)充,只是比 Collection
接口更加嚴(yán)格了。與 List
接口不同的是, Set
接口中元素?zé)o序,并且都會(huì)以某種規(guī)則保證存入的元素不出現(xiàn)重復(fù)。Set
集合有多個(gè)子類(lèi),這里我們介紹其中的 java.util.HashSet
、 java.util.LinkedHashSet
這兩個(gè)集合。
tips:Set集合取出元素的方式可以采用:迭代器、增強(qiáng)for。
一、HashSet集合介紹
java.util.HashSet
是Set
接口的一個(gè)實(shí)現(xiàn)類(lèi),它所存儲(chǔ)的元素是不可重復(fù)的,并且元素都是無(wú)序的(即存取順序不一致)。java.util.HashSet
底層的實(shí)現(xiàn)其實(shí)是一個(gè)java.util.HashMap
支持。
HashSet
是根據(jù)對(duì)象的哈希值來(lái)確定元素在集合中的存儲(chǔ)位置,因此具有良好的存取和查找性能。保證元素唯一性的方式依賴(lài)于:hashCode
與equals
方法。
我們先來(lái)使用一下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é)果如下,說(shuō)明集合中不能存儲(chǔ)重復(fù)元素:
cba
abc
bac
tips:根據(jù)結(jié)果我們發(fā)現(xiàn)字符串"cba"只存儲(chǔ)了一個(gè),也就是說(shuō)重復(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í),通過(guò)key值依次查找的效率較低。而JDK1.8中,哈希表存儲(chǔ)采用數(shù)組+鏈表+紅黑樹(shù)實(shí)現(xiàn),當(dāng)鏈表長(zhǎng)度超過(guò)閾值(8)時(shí),將鏈表轉(zhuǎn)換為紅黑樹(shù),這樣大大減少了查找時(shí)間。
簡(jiǎn)單的來(lái)說(shuō),哈希表是由數(shù)組+鏈表+紅黑樹(shù)(JDK1.8增加了紅黑樹(shù)部分)實(shí)現(xiàn)的,
如下圖所示:
看到這張圖就有人要問(wèn)了,這個(gè)是怎么存儲(chǔ)的呢?
為了方便大家的理解我們結(jié)合一個(gè)存儲(chǔ)流程圖來(lái)說(shuō)明一下:
總而言之,JDK1.8引入紅黑樹(shù)大程度優(yōu)化了HashMap的性能,那么對(duì)于我們來(lái)講保證HashSet集合元素的唯一,其實(shí)就是根據(jù)對(duì)象的hashCode和equals方法來(lái)決定的。如果我們往集合中存放自定義的對(duì)象,那么保證其唯一,就必須復(fù)寫(xiě)hashCode和equals方法建立屬于當(dāng)前對(duì)象的比較方式。
三、HashSet存儲(chǔ)自定義類(lèi)型元素
給HashSet中存放自定義類(lèi)型元素時(shí),需要重寫(xiě)對(duì)象中的hashCode和equals方法,建立自己的比較方式,才能保證HashSet集合中的對(duì)象唯一。
創(chuàng)建自定義Student類(lèi):
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)建集合對(duì)象 該集合中存儲(chǔ) Student類(lèi)型對(duì)象 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)去是沒(méi)有順序的,那么我們要保證有序,怎么辦呢?
在HashSet下面有一個(gè)子類(lèi)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集合及其子類(lèi)HashSet與LinkedHashSet詳解的文章就介紹到這了,更多相關(guān)Java Set集合 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在Java中Collection的一些常用方法總結(jié)
今天給大家?guī)?lái)的知識(shí)是關(guān)于Java的,文章圍繞著Java中Collection的一些常用方法展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06Java實(shí)現(xiàn)LeetCode(54.螺旋矩陣)
這篇文章主要介紹了Java實(shí)現(xiàn)LeetCode(螺旋矩陣),本文列出題目和寫(xiě)題的思路。給出完整的解法代碼,需要的朋友可以參考下2021-06-06SpringBoot中實(shí)現(xiàn)訂單30分鐘自動(dòng)取消的三種方案分享
在電商和其他涉及到在線支付的應(yīng)用中,通常需要實(shí)現(xiàn)一個(gè)功能:如果用戶在生成訂單后的一定時(shí)間內(nèi)未完成支付,系統(tǒng)將自動(dòng)取消該訂單,本文將詳細(xì)介紹基于Spring Boot框架實(shí)現(xiàn)訂單30分鐘內(nèi)未支付自動(dòng)取消的幾種方案,并提供實(shí)例代碼,需要的朋友可以參考下2023-10-10SpringBoot 使用 FTP 操作文件的過(guò)程(刪除、上傳、下載文件)
這篇文章主要介紹了SpringBoot 使用 FTP 操作文件,主要包括配置ftp服務(wù)器,上傳、刪除、下載文件操作,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12Java Fluent Mybatis實(shí)戰(zhàn)之構(gòu)建項(xiàng)目與代碼生成篇上
Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國(guó)內(nèi)又以Mybatis用的多,基于mybatis上的增強(qiáng)框架,又有mybatis plus和TK mybatis等。今天我們介紹一個(gè)新的mybatis增強(qiáng)框架 fluent mybatis2021-10-10淺談SpringBoot實(shí)現(xiàn)自動(dòng)裝配的方法原理
SpringBoot的自動(dòng)裝配是它的一大特點(diǎn),可以大大提高開(kāi)發(fā)效率,減少重復(fù)性代碼的編寫(xiě)。本文將詳細(xì)講解SpringBoot如何實(shí)現(xiàn)自動(dòng)裝配,需要的朋友可以參考下2023-05-05SpringBoot切面實(shí)現(xiàn)token權(quán)限校驗(yàn)詳解
這篇文章主要介紹了SpringBoot切面實(shí)現(xiàn)token權(quán)限校驗(yàn)詳解,要實(shí)現(xiàn)權(quán)限校驗(yàn),首先數(shù)據(jù)表和實(shí)體類(lèi)上需要有權(quán)限字段,我的表中permission和gender是通過(guò)外鍵約束permission表和gender表實(shí)現(xiàn)枚舉的,因?yàn)榭赏卣剐愿?需要的朋友可以參考下2024-01-01