日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

Java集合框架:EnumMap

發(fā)布時(shí)間:2023/11/27 生活经验 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java集合框架:EnumMap 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

EnumMap定義

package java.util;import java.util.Map.Entry;
import sun.misc.SharedSecrets;
public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>implements java.io.Serializable, Cloneable{private final Class<K> keyType;private transient K[] keyUniverse;private transient Object[] vals;private transient int size = 0;
}

??keyType變量是EnumMap的key泛型的類對(duì)象,EnumMap依據(jù)這個(gè)類型。能夠獲得keyUniverse的內(nèi)容。vals存放的是與keyUniverse映射的值。假設(shè)沒(méi)有映射則為null,假設(shè)映射為null則會(huì)特殊處理成NULL。NULL的定義例如以下:

 private static final Object NULL = new Object() {public int hashCode() {return 0;}public String toString() {return "java.util.EnumMap.NULL";}};

??對(duì)于值NULL的處理相似WeakHashMap的特殊處理,會(huì)有兩個(gè)方法:

    private Object maskNull(Object value) {return (value == null ? NULL : value);}private V unmaskNull(Object value) {return (V) (value == NULL ? null : value);}

??這樣能夠區(qū)分vals中是null(即沒(méi)有映射)還是NULL(即映射為null);
??EnumMap的size是依據(jù)vals中的非null(包含NULL)的值的個(gè)數(shù)確定的,比方put方法:

    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);}

??typeCheck推斷key的類對(duì)象或者父類對(duì)象是否與keyType相等,假設(shè)不相等則拋出ClassCastException異常。
??注意EnumMap并沒(méi)有相似HashMap的resize的過(guò)程,也沒(méi)有載入因子的概念,由于在一個(gè)EnumMap創(chuàng)建的時(shí)候,keyUniverse和vals的大小就固定。


EnumMap使用

??先舉個(gè)小樣例:

package collections.map;import java.util.EnumMap;
import java.util.Map;public class EnumMapTest
{public enum Color{RED,BLUE,BLACK,YELLOW,GREEN;}public static void main(String[] args){EnumMap<Color,String> map = new EnumMap<>(Color.class);EnumMap<Color,String> map = new EnumMap<>(Color.class);map.put(Color.YELLOW, "黃色");map.put(Color.RED, "紅色");map.put(Color.BLUE, null);
//        map.put(null, "無(wú)");   //會(huì)報(bào)NullPonitException的錯(cuò)誤map.put(Color.BLACK, "黑色");map.put(Color.GREEN, "綠色");for(Map.Entry<Color,String> entry:map.entrySet()){System.out.println(entry.getKey()+":"+entry.getValue());}System.out.println(map);}
}

??執(zhí)行結(jié)果:

RED:紅色
BLUE:null
BLACK:黑色
YELLOW:黃色
GREEN:綠色
{RED=紅色, BLUE=null, BLACK=黑色, YELLOW=黃色, GREEN=綠色}

??EnumMap的key不同意為null,value能夠?yàn)閚ull,依照key在enum中的順序進(jìn)行保存。非線程安全。能夠用工具類Collections進(jìn)行包裝成線程安全的:

Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));

??有關(guān)enum的應(yīng)用知識(shí)能夠參考《Java枚舉類型enum》。
??EnumMap的基本操作都比較快,都在常量時(shí)間內(nèi)完畢,基本上(但不保證)比HashMap快。
??EnumMap有三個(gè)構(gòu)造函數(shù):

  • public EnumMap(Class<K> keyType);
  • public EnumMap(EnumMap<K, ?

    extends V> m);

  • public EnumMap(Map<K, ?

    extends V> m) ;

??前兩個(gè)構(gòu)造函數(shù)一目了然,對(duì)第三個(gè)構(gòu)造函數(shù)進(jìn)行分析:

Map<Integer,Integer> map1 = new HashMap<>();map1.put(1, 1);map1.put(3, 3);map1.put(2, 2);Map<Integer,Integer> map2 = new EnumMap<>(map1);//編譯器提示錯(cuò)誤:Cannot infer type arguments for EnumMap<>

??這個(gè)是由于Integer并非extends Enum;
??這里變換一下,採(cǎi)用Map

Map<Enum,Integer> map1 = new HashMap<>();map1.put(Color.YELLOW, 1);map1.put(Color.RED, 3);map1.put(Color.BLUE, 2);Map<Enum,Integer> map2 = new EnumMap<>(map1);for(Map.Entry entry:map2.entrySet()){System.out.println(entry.getKey()+":"+entry.getValue());}System.out.println(map2);System.out.println(map2.size());

??能夠正常執(zhí)行。輸出結(jié)果:

RED:3
BLUE:2
YELLOW:1
{RED=3, BLUE=2, YELLOW=1}
3

??相信大家能夠總結(jié)個(gè)一二了吧。


EnumMap用途

??《Effective Java》中作者建議用EnumMap取代敘述索引。最好不要用序數(shù)來(lái)索引數(shù)組,而要使用EnumMap
??這里採(cǎi)用《Effective Java》書(shū)中的樣例來(lái)舉例。

     public static class Herb{public enum Type{ANNUAL, PERENNIAL, BIENNTAL}private final String name;private final Type type;public Herb(String name, Type type){this.name = name;this.type = type;}public Type getType(){return type;}@Overridepublic String toString(){return name;}}

??如今用一座種滿香草的花園,想要依照類型(一年生、多年生、兩年生,即上面Type的類型)進(jìn)行組織之后將這些植物列出來(lái)。假設(shè)使用數(shù)組實(shí)現(xiàn)的話。須要構(gòu)建三個(gè)集合,每種類型一個(gè)。而且遍歷整座花園,將每種香草放到相應(yīng)的集合中。

Herb[] garden = new Herb[]{new Herb("f1",Herb.Type.ANNUAL),new Herb("f2",Herb.Type.PERENNIAL),new Herb("f3",Herb.Type.BIENNTAL),new Herb("f4",Herb.Type.PERENNIAL),new Herb("f5",Herb.Type.ANNUAL),new Herb("f6",Herb.Type.BIENNTAL),new Herb("f7",Herb.Type.ANNUAL),new Herb("f8",Herb.Type.BIENNTAL),new Herb("f9",Herb.Type.PERENNIAL)};Set<Herb>[] herbsByType = (Set<Herb>[]) new Set[Herb.Type.values().length];for(int i=0;i<herbsByType.length;i++){herbsByType[i] = new HashSet<Herb>();}for(Herb h:garden){herbsByType[h.type.ordinal()].add(h);}for(int i=0;i<herbsByType.length;i++){System.out.printf("%s:%s%n", Herb.Type.values()[i],herbsByType[i]);}

??執(zhí)行結(jié)果:

ANNUAL:[f5, f7, f1]
PERENNIAL:[f4, f2, f9]
BIENNTAL:[f8, f3, f6]

??這樣的方法確實(shí)可行。可是影藏著很多問(wèn)題。由于數(shù)組不能和泛型兼容。程序須要進(jìn)行未受檢的轉(zhuǎn)換,而且不能正確無(wú)誤地進(jìn)行編譯。由于數(shù)組不知道它的索引代表著什么,你必須手工標(biāo)注這些索引的輸出。可是這樣的方法最嚴(yán)重的問(wèn)題在于。當(dāng)你訪問(wèn)一個(gè)依照枚舉的敘述進(jìn)行索引的數(shù)組時(shí),使用正確的int值就是你的職責(zé)了。int不能提供枚舉的類型安全。
??可是你能夠用EnumMap改善這個(gè)程序:

Herb[] garden = new Herb[]{new Herb("f1",Herb.Type.ANNUAL),new Herb("f2",Herb.Type.PERENNIAL),new Herb("f3",Herb.Type.BIENNTAL),new Herb("f4",Herb.Type.PERENNIAL),new Herb("f5",Herb.Type.ANNUAL),new Herb("f6",Herb.Type.BIENNTAL),new Herb("f7",Herb.Type.ANNUAL),new Herb("f8",Herb.Type.BIENNTAL),new Herb("f9",Herb.Type.PERENNIAL)};Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<>(Herb.Type.class);for(Herb.Type t : Herb.Type.values()){herbsByType.put(t, new HashSet<Herb>());}for(Herb h:garden){herbsByType.get(h.type).add(h);}System.out.println(herbsByType);

??執(zhí)行結(jié)果:

{ANNUAL=[f7, f1, f5], PERENNIAL=[f4, f2, f9], BIENNTAL=[f8, f6, f3]}

??這段程序更剪短、更清楚,也更安全。執(zhí)行速度方面能夠與使用序數(shù)的數(shù)組相媲美。注意EnumMap構(gòu)造器採(cǎi)用鍵類型的Class對(duì)象:這是一個(gè)有限制的類型令牌,它提供了執(zhí)行時(shí)的泛型信息


總結(jié)

??EnumMap是專門(mén)為枚舉類型量身定做的Map實(shí)現(xiàn)。

盡管使用其他的Map實(shí)現(xiàn)(如HashMap)也能完畢枚舉類型實(shí)例到值得映射,可是使用EnumMap會(huì)更加高效:它僅僅能接收同一枚舉類型的實(shí)例作為鍵值。而且由于枚舉類型實(shí)例的數(shù)量相對(duì)固定而且有限,所以EnumMap使用數(shù)組來(lái)存放與枚舉類型相應(yīng)的值。這使得EnumMap的效率很高。EnumMap在內(nèi)部使用枚舉類型的ordinal()得到當(dāng)前實(shí)例的聲明次序,并使用這個(gè)次序維護(hù)枚舉類型實(shí)例相應(yīng)值在數(shù)組的位置。


參考資料:
1. 《Java枚舉類型enum》
2. 《Effective Java(Second Edition)》. Joshua Bloch.
3. 《EnumMap與Enumset的使用 》

轉(zhuǎn)載于:https://www.cnblogs.com/yangykaifa/p/7388563.html

總結(jié)

以上是生活随笔為你收集整理的Java集合框架:EnumMap的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。