1.EnumSet示例及核心源碼分析
package com.landon.mavs.example.collection;

import java.util.EnumSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.landon.mavs.example.collection.EnumMapExample.NBA;


/** *//**
*
* EnumSet example
*
* <pre>
* 1.public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
* implements Cloneable, java.io.Serializable
* 2.其內(nèi)部元素為枚舉,另外可以看到其是一個(gè)抽象類abstract
* 3.其在內(nèi)部表示為位向量,足以用作傳統(tǒng)上基于 int 的“位標(biāo)志”的替換形式.(即類似0x1000000,按bit存儲(chǔ),用位運(yùn)算進(jìn)行相關(guān)操作)
* 4. 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);
* }
* 從源碼上看:即根據(jù)傳入的枚舉類型判斷組成長度,64以內(nèi)則返回RegularEnumSet,否則JumboEnumSet
* 5.從其內(nèi)部API方法看,全部是靜態(tài)方法static.
* 6.以RegularEnumSet內(nèi)部方法實(shí)現(xiàn):
* public boolean add(E e) {
* typeCheck(e);
* // elements默認(rèn)為0
* long oldElements = elements;
* elements |= (1L << ((Enum)e).ordinal());
* return elements != oldElements;
* }
* 從add源碼上看:1.取枚舉值的ordinal,初始為0. 2.1 << ordinal 3.與elements做|運(yùn)算
* 舉例:a.添加ordinal為0,則計(jì)算后elements為1
* b.添加ordinal為1,則計(jì)算后elements為(10 | 01) = 11
* c.添加ordinal為2,則計(jì)算后elements為(011 | 100) = 111
* ->所以從源碼上看,其就是用一個(gè)long來存儲(chǔ)枚舉.你懂得(long是64位).
*
* public boolean contains(Object e) {
* if (e == null)
* return false;
* Class eClass = e.getClass();
* if (eClass != elementType && eClass.getSuperclass() != elementType)
* return false;
*
* return (elements & (1L << ((Enum)e).ordinal())) != 0;
* }
* 從contains源碼上看:最重要的是最好一句:(elements & (1L << ((Enum)e).ordinal())) != 0
* 1.1L << ((Enum)e).ordinal()
* 2.與elements做&運(yùn)算
* 舉例:如果ordinal為2,則通過第一步計(jì)算值為4(100) & 111(之前已經(jīng)添加過ordinal為2的元素,高位至1)
* ->則高位肯定為1,則表示有這個(gè)元素
* 總結(jié):利用一個(gè)long和位運(yùn)算實(shí)現(xiàn)EnumSet的快速存儲(chǔ)和判斷.
* 7.至于JumboEnumSet的內(nèi)部實(shí)現(xiàn):則是用一個(gè)long elements[]實(shí)現(xiàn),只是對(duì)long的擴(kuò)展,其實(shí)現(xiàn)細(xì)節(jié)差不太多,這里不詳述了
* </pre>
*
* @author landon
*
*/

public class EnumSetExample
{
private static final Logger LOGGER = LoggerFactory
.getLogger(EnumSetExample.class);


public static void main(String[] args)
{
// allOf:一個(gè)包含指定元素類型的所有元素的枚舉 set
EnumSet<NBA> allofEnumSet = EnumSet.allOf(NBA.class);
// [allofEnumSet:[MAVS, LAKERS, PACERS]]
LOGGER.debug("allofEnumSet:{}", allofEnumSet);

// noneOf:創(chuàng)建一個(gè)具有指定元素類型的空枚舉 set
EnumSet<NBA> noneofEnumSet = EnumSet.noneOf(NBA.class);
// 添加一個(gè)元素
noneofEnumSet.add(NBA.LAKERS);
// [noneofEnumSet:[LAKERS]]
LOGGER.debug("noneofEnumSet:{}", noneofEnumSet);

// complementOf:取補(bǔ)
EnumSet<NBA> complementOfEnumSet = EnumSet.complementOf(noneofEnumSet);
// [[complementOfEnumSet:[MAVS, PACERS]]
LOGGER.debug("complementOfEnumSet:{}", complementOfEnumSet);

// copyof:拷貝
EnumSet<NBA> copyofEnumSet = EnumSet.copyOf(complementOfEnumSet);
// [copyofEnumSet:[MAVS, PACERS]]
LOGGER.debug("copyofEnumSet:{}", copyofEnumSet);

// of(E e):最初包含指定元素的枚舉 set
EnumSet<NBA> ofEnumSet = EnumSet.of(NBA.PACERS);
LOGGER.debug("ofEnumSet:{}", ofEnumSet);

// of(E first,E
rest)

NBA[] nbas = new NBA[]
{ NBA.LAKERS, NBA.MAVS, NBA.PACERS };
EnumSet<NBA> ofEnumSet2 = EnumSet.of(NBA.PACERS, nbas);
// 從輸出可以可以看到:是按照枚舉的ordinal順序輸出的
LOGGER.debug("ofEnumSet2:{}", ofEnumSet2);

// range(E from, E to) [from,to]
EnumSet<NBA> rangeEnumSet = EnumSet.range(NBA.MAVS, NBA.PACERS);
LOGGER.debug("rangeEnumSet:{}", rangeEnumSet);

// Exception in thread "main" java.lang.IllegalArgumentException: PACERS
// > LAKERS
// 拋出了異常,所以from和to的順序不能顛倒(按照枚舉的ordinal順序)
EnumSet<NBA> rangeEnumSet2 = EnumSet.range(NBA.PACERS, NBA.LAKERS);
LOGGER.debug("rangeEnumSet2:{}", rangeEnumSet2);
}

}

2.EnumMap示例及核心源碼分析
package com.landon.mavs.example.collection;

import java.util.Collection;
import java.util.EnumMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/** *//**
*
* EnumMap example
*
* <pre>
* 1.public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
* implements java.io.Serializable, Cloneable
* 2.可見EnumMap的key是一個(gè)枚舉
* 3.枚舉映射在內(nèi)部表示為數(shù)組
* 4. 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的源碼可以看到,是利用Enum的ordinal作為數(shù)組的索引.所以實(shí)現(xiàn)緊湊且高效
* </pre>
*
* @author landon
*
*/

public class EnumMapExample
{
private static final Logger LOGGER = LoggerFactory
.getLogger(EnumMapExample.class);


/** *//**
*
* Nba球隊(duì)枚舉,分別是小牛,湖人,步行者
*
* @author landon
*
*/

static enum NBA
{
MAVS, LAKERS, PACERS,
}


public static void main(String[] args)
{
// 構(gòu)造函數(shù)public EnumMap(Class<K> keyType),參數(shù)表示key類型
// 泛型只是編譯起作用
EnumMap<NBA, String> em = new EnumMap<NBA, String>(NBA.class);

// put順序不是根據(jù)枚舉的ordinal順序
em.put(NBA.LAKERS, "kobe");
em.put(NBA.MAVS, "dirk");
em.put(NBA.PACERS, "miller");

// get方法會(huì)首先檢查參數(shù)的class是否valid(與keyTypeClass對(duì)比)
LOGGER.debug("mavs_player:{}", em.get(NBA.MAVS));
// 類型檢查失敗則返回null
LOGGER.debug("mavs_player:{}", em.get("mavs"));

Collection<String> values = em.values();
// 從輸出可以看到,視圖的內(nèi)部順序是枚舉定義的順序.
// 輸出em.values:[dirk, kobe, miller]
LOGGER.debug("em.values:{}", values.toString());

// 拋出空指針異常Exception in thread "main" java.lang.NullPointerException
// 所以key不允許為null
em.put(null, "tmac");
}
}

posted on 2014-02-03 18:34
landon 閱讀(1645)
評(píng)論(0) 編輯 收藏 所屬分類:
Program 、
Sources