首頁 > 軟體

Java 中很好用的資料結構EnumSet

2022-05-16 13:00:09

前言

Java 中常規的集合工具,相比大家都熟練於胸,但是如果說有一個集合類你不一定知道或者說肯定沒用過,你相不相信呢?今天跟大家介紹的就是 java.util.EnumMap,也是 java.util 包下面的一個集合類,同樣的也有對應的的 java.util.EnumSet,下面我們看一下吧。

Map和 Set 結構在我們日常工作的使用的特別多,經常會用來存放資料或者引數傳遞,不過有些場景在使用 Map 的時候,不知道大家會不會感受到一絲絲的不安,畢竟 Map 的資料設定我們沒辦法控制,完全不知道別人會 put 一些什麼樣的資料進去,或者說如果某些場景我們 Map 的資料 Key 的型別和個數是固定,那在這種情況的下,我們如何提升系統的安全性和效能呢?

這個時候我們就可以考慮使用 EnumMapEnumMap顧名思義首先是一個 Map,其次它的 key只能是列舉,大家都知道列舉中的範例個數是固定的,而且還是預編譯的,所以在很大程度上保證了資料的安全性,同時也可以提升一定的效能。

EnumMap

下面我們來看下如何使用 EnumMap,首先我們需要建立一個列舉 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", "藍色"),
  RED("red", "紅色"),
  ;
  public String color;
  public String desc;

  Color(String color, String desc) 
  {
    this.color = color;
    this.desc = desc;
  }
}

在建立一個測試類:

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, "我是一個藍色列舉");
    System.out.println(enumMap.get(Color.BLUE));
  }
}

 我們可以看到構造 EnumMap 的時候需要傳入一個列舉類,後續的 put 和 get 都跟普通的 Map 一樣,只不過這個時候 put 的時候 key 必須是該列舉範例了。接下來我們看下EnumMap的 put 和 get 方法是如何實現的,檢視 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);
    }

在進行 put的時候,會先進行型別檢查,如果說傳進來的不是列舉或者說不是在構造的時候指定的列舉,這裡就會丟擲異常。當型別檢查通過以後,會通過列舉的 ordinal() 方法獲取該列舉範例的索引,這個方法會返回一個 int 值,返回的值跟列舉在編寫的時候的順序有關係,比如說我們上面建立的 Color 列舉,Color.BLUE.ordinal() 會返回 0Color.RED.ordinal() 會返回 1。拿到索引過後,就會在對應的陣列位置上放上 value 值。

 獲取資料的時候就更簡單了,直接通過 key 獲取到索引,然後從陣列中那去資料即可。

  public V get(Object key) 
  {
        return (isValidKey(key) ?
                unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
    }

可以看到整個 EnumMap的 put和 get的效率是非常高的,都是在一維陣列中直接根據索引定向處理。所以後續大家在類似的場景中可以嘗試使用這種方式來提升效能。

EnumSet

說完了 EnumMap 我們再來看看 EnumSetEnumSet 是一個用來操作 Enum 的集合,是一個抽象類,它有兩個繼承類,JumboEnumSet 和 RegularEnumSet。在使用的時候,需要確定列舉型別。通過下面的方式可以建立一個空的 EnumSet,在後續進行使用。

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的構造方式相對會多一點,我們可以建立空的集合,同時我們也可以直接根據建立一個完整的集合,沒必要建立空的然後再進行 add操作,如下所示:

  public static void main(String[] args) 
  {
    EnumSet<Color> enumSet = EnumSet.allOf(Color.class);
    System.out.println(enumSet.size());
  }

另外前面提到會使用到列舉的 ordinal()方式,所以我們在構造 EnumSet 的時候還可以只構造指定兩個列舉範圍之間的所有列舉值,這裡要注意 range方法的第二哥引數的列舉不能在第一個列舉前面。

EnumSet.range(Color.BLUE,Color.RED);

還可以通過 EnumSet的 of 方法來構造指定的列舉集合,通過原始碼我們可以發現不管是通過什麼方法了構造,底層都是先構造一個空集合,然後將對應的列舉元素新增進行。構造空集合的實現邏輯如下,這裡我們可以看到,當列舉個數大於 64 的時候,採用的是 JumboEnumSet 這個子類,否則都是 RegularEnumSet這個子類,正常來說一個列舉的範例個數超過 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);
    }

到此這篇關於Java 中很好用的資料結構EnumSet的文章就介紹到這了,更多相關java  EnumSet內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com