Java?中很好用的數(shù)據(jù)結(jié)構(gòu)(你絕對沒用過)
前言
Java 中常規(guī)的集合工具,相比大家都熟練于胸,但是如果說有一個集合類你不一定知道或者說肯定沒用過,你相不相信呢?今天跟大家介紹的就是 java.util.EnumMap
,也是 java.util
包下面的一個集合類,同樣的也有對應(yīng)的的 java.util.EnumSet,
下面我們看一下吧。
Map
和 Set
結(jié)構(gòu)在我們?nèi)粘9ぷ鞯氖褂玫奶貏e多,經(jīng)常會用來存放數(shù)據(jù)或者參數(shù)傳遞,不過有些場景在使用 Map 的時候,不知道大家會不會感受到一絲絲的不安,畢竟 Map
的數(shù)據(jù)設(shè)置我們沒辦法控制,完全不知道別人會 put 一些什么樣的數(shù)據(jù)進(jìn)去,或者說如果某些場景我們 Map
的數(shù)據(jù) Key
的類型和個數(shù)是固定,那在這種情況的下,我們?nèi)绾翁嵘到y(tǒng)的安全性和性能呢?
這個時候我們就可以考慮使用 EnumMap
,EnumMap
顧名思義首先是一個 Map
,其次它的 key
只能是枚舉,大家都知道枚舉中的實例個數(shù)是固定的,而且還是預(yù)編譯的,所以在很大程度上保證了數(shù)據(jù)的安全性,同時也可以提升一定的性能。
EnumMap
下面我們來看下如何使用 EnumMap
,首先我們需要創(chuàng)建一個枚舉 Color
。
package com.ziyou.demo.enums; /** * <br> * <b>Function:</b><br> * <b>Author:</b><br> * <b>Date:</b>2022-04-17 <br> * <b>Desc:</b>無<br> */ public enum Color { BLUE("blue", "藍(lán)色"), RED("red", "紅色"), ; public String color; public String desc; Color(String color, String desc) { this.color = color; this.desc = desc; } }
在創(chuàng)建一個測試類
package com.ziyou.demo.enums; import java.util.EnumMap; /** * <br> * <b>Function:</b><br> * <b>Author:</b><br> * <b>Date:</b>2022-04-17 <br> * <b>Desc:</b>無<br> */ public class ColorTest { public static void main(String[] args) { EnumMap<Color, String> enumMap = new EnumMap<>(Color.class); enumMap.put(Color.RED, "我是一個紅色枚舉"); enumMap.put(Color.BLUE, "我是一個藍(lán)色枚舉"); System.out.println(enumMap.get(Color.BLUE)); } }
我們可以看到構(gòu)造 EnumMap
的時候需要傳入一個枚舉類,后續(xù)的 put
和 get
都跟普通的 Map
一樣,只不過這個時候 put
的時候 key
必須是該枚舉實例了。接下來我們看下EnumMap
的 put
和 get
方法是如何實現(xiàn)的,查看 JDK
源碼我們可以看到。
public V put(K key, V value) { typeCheck(key); int index = key.ordinal(); Object oldValue = vals[index]; vals[index] = maskNull(value); if (oldValue == null) size++; return unmaskNull(oldValue); }
在進(jìn)行 put
的時候,會先進(jìn)行類型檢查,如果說傳進(jìn)來的不是枚舉或者說不是在構(gòu)造的時候指定的枚舉,這里就會拋出異常。當(dāng)類型檢查通過以后,會通過枚舉的 ordinal()
方法獲取該枚舉實例的索引,這個方法會返回一個 int
值,返回的值跟枚舉在編寫的時候的順序有關(guān)系,比如說我們上面創(chuàng)建的 Color
枚舉,Color.BLUE.ordinal()
會返回 0
,Color.RED.ordinal()
會返回 1
。拿到索引過后,就會在對應(yīng)的數(shù)組位置上放上 value
值。
獲取數(shù)據(jù)的時候就更簡單了,直接通過 key 獲取到索引,然后從數(shù)組中那去數(shù)據(jù)即可。
public V get(Object key) { return (isValidKey(key) ? unmaskNull(vals[((Enum<?>)key).ordinal()]) : null); }
可以看到整個 EnumMap
的 put
和 get
的效率是非常高的,都是在一維數(shù)組中直接根據(jù)索引定向處理。所以后續(xù)大家在類似的場景中可以嘗試使用這種方式來提升性能。
EnumSet
說完了 EnumMap
我們再來看看 EnumSet
,EnumSe
t 是一個用來操作 Enum
的集合,是一個抽象類,它有兩個繼承類,JumboEnumSet
和 RegularEnumSet
。在使用的時候,需要確定枚舉類型。通過下面的方式可以創(chuàng)建一個空的 EnumSet
,在后續(xù)進(jìn)行使用。
public static void main(String[] args) { EnumSet<Color> enumSet = EnumSet.noneOf(Color.class); enumSet.add(Color.BLUE); enumSet.add(Color.RED); System.out.println(enumSet.size()); }
EnumSet
的構(gòu)造方式相對會多一點,我們可以創(chuàng)建空的集合,同時我們也可以直接根據(jù)創(chuàng)建一個完整的集合,沒必要創(chuàng)建空的然后再進(jìn)行 add
操作,如下所示:
public static void main(String[] args) { EnumSet<Color> enumSet = EnumSet.allOf(Color.class); System.out.println(enumSet.size()); }
另外前面提到會使用到枚舉的 ordinal()
方式,所以我們在構(gòu)造 EnumSet
的時候還可以只構(gòu)造指定兩個枚舉范圍之間的所有枚舉值,這里要注意 range
方法的第二哥參數(shù)的枚舉不能在第一個枚舉前面。
EnumSet.range(Color.BLUE,Color.RED);
還可以通過 EnumSet
的 of
方法來構(gòu)造指定的枚舉集合,通過源碼我們可以發(fā)現(xiàn)不管是通過什么方法了構(gòu)造,底層都是先構(gòu)造一個空集合,然后將對應(yīng)的枚舉元素添加進(jìn)行。構(gòu)造空集合的實現(xiàn)邏輯如下,這里我們可以看到,當(dāng)枚舉個數(shù)大于 64
的時候,采用的是 JumboEnumSet
這個子類,否則都是 RegularEnumSet
這個子類,正常來說一個枚舉的實例個數(shù)超過 64
的會比較少吧。
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) { Enum<?>[] universe = getUniverse(elementType); if (universe == null) throw new ClassCastException(elementType + " not an enum"); if (universe.length <= 64) return new RegularEnumSet<>(elementType, universe); else return new JumboEnumSet<>(elementType, universe); }
到此這篇關(guān)于Java 中一個你絕對沒用過,但是很好用的數(shù)據(jù)結(jié)構(gòu)的文章就介紹到這了,更多相關(guān)java數(shù)據(jù)結(jié)構(gòu)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java通過ssh連接服務(wù)器執(zhí)行shell命令詳解及實例
這篇文章主要介紹了java通過ssh連接服務(wù)器執(zhí)行shell命令詳解及實例方法的相關(guān)資料2017-02-02MyBatis動態(tài)SQL標(biāo)簽用法實例詳解
本文通過實例代碼給大家介紹了MyBatis動態(tài)SQL標(biāo)簽用法,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-07-07JAVA?GUI基礎(chǔ)與MouseListener用法
這篇文章主要介紹了JAVA?GUI基礎(chǔ)與MouseListener用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12Java中volatile關(guān)鍵字實現(xiàn)原理
本文詳細(xì)解讀一下volatile關(guān)鍵字如何保證變量在多線程之間的可見性,對Java中volatile關(guān)鍵字實現(xiàn)原理感興趣的朋友一起通過本文學(xué)習(xí)吧2017-06-06JAVA中方法的聲明及使用方式(繼承、多態(tài)、封裝)
這篇文章主要介紹了JAVA中方法的聲明及使用方式(繼承、多態(tài)、封裝),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02