在日常的開發(fā)過程中,很多時候我們需要枚舉類(enum)來表示對象的各種狀態(tài),并且每個狀態(tài)往往會關(guān)聯(lián)到指定的數(shù)字,如:

    private enum Color {
        RED(11), GREEN(21), YELLOW(31), BLACK(160);
		...
    };

或者用枚舉類來表示一系列狀態(tài)的轉(zhuǎn)變關(guān)系:

    enum Week{
        SUNDAY(1), MONDAY(2), TUESDAY(3), WEDNESDAY(4), THRUSDAY(5), FRIDAY(6), SATRUDAY7);
		...
    };

那么,如何用最少的存儲來實現(xiàn)這類需求,答案很簡單,位存儲。如 1bit 表示 0,1 兩種狀態(tài),2bit 表示 00,01,10,11 四種狀態(tài),所以我們可以用一個 long 類型(64bit)/int類型(32bit)存儲多種狀態(tài),如下圖:

 

photoshop培訓,電腦培訓,電腦維修培訓,移動軟件開發(fā)培訓,網(wǎng)站設計培訓,網(wǎng)站建設培訓

 

位存儲示例

 

但是每新建一個枚舉類都需要自己操作 bit

  1. 導致程序不易理解

  2. 容易出錯,耗費精力

Hadoop hdfs 的實現(xiàn)中,也遇到類似的問題,它借助于 LongBitFormat.java 類封裝了 bit操作:

    public class LongBitFormat implements Serializable {
    private static final long serialVersionUID = 1L;

    private final String NAME;
    /** Bit offset */
    private final int OFFSET;
    /** Bit length */
    private final int LENGTH;
    /** Minimum value */
    private final long MIN;
    /** Maximum value */
    private final long MAX;
    /** Bit mask */
    private final long MASK;

    public LongBitFormat(String name, LongBitFormat previous, int length,
                         long min) {
        NAME = name;
        OFFSET = previous == null ? 0 : previous.OFFSET + previous.LENGTH;
        LENGTH = length;
        MIN = min;
        MAX = ((-1L) >>> (64 - LENGTH));//移動的位數(shù),右移64-Leng位,相當于保留length位
        MASK = MAX << OFFSET;
    }

    /** Retrieve the value from the record. */
    public long retrieve(long record) {
        return (record & MASK) >>> OFFSET;
    }

    /** Combine the value to the record. */
    public long combine(long value, long record) {
        if (value < MIN) {
            throw new IllegalArgumentException(
                    "Illagal value: " + NAME + " = " + value + " < MIN = " + MIN);
        }
        if (value > MAX) {
            throw new IllegalArgumentException(
                    "Illagal value: " + NAME + " = " + value + " > MAX = " + MAX);
        }
        return (record & ~MASK) | (value << OFFSET);
    }

    public long getMin() {
        return MIN;
    }
}

當然,你也可以實現(xiàn) IntBigFormat,ShortBitFormat 等

首先分析該類的構(gòu)造方法:

        NAME = name;
        OFFSET = previous == null? 0: previous.OFFSET + previous.LENGTH;
        LENGTH = length;
        MIN = min;
        MAX = ((-1L) >>> (64 - LENGTH));//移動的位數(shù),右移64-Leng位,相當于保留length位
        MASK = MAX << OFFSET;

字段:
NAME:狀態(tài)名,可自定義

OFFSET:該狀態(tài)在 long 字節(jié)中的偏移

LENGTH:用多少位存儲該狀態(tài)關(guān)聯(lián)的數(shù)字

MIN:該狀態(tài)關(guān)聯(lián)的最小值

MAX:該狀態(tài)關(guān)聯(lián)的最大值

MASK:掩碼,(OFFSET~OFFSET+LENGTH - 1) == 1

類方法:
retrieve(long record):獲得該狀態(tài)關(guān)聯(lián)的數(shù)字

combine(long value, long record):將一個 value 加到 record 中,例如:將 value 值對應的枚舉類存儲在 32-40,則先將 32-40bits 清零,再將value 對應的二進制加入到 32-40

那么如何使用該類:

public class LongFormatTest {

    static enum HeaderFormat {
        PREFERRED_BLOCK_SIZE(null, 48, 1),
        REPLICATION(PREFERRED_BLOCK_SIZE.BITS, 12, 1),
        STORAGE_POLICY_ID(REPLICATION.BITS, 4, 0);

        private final LongBitFormat BITS;

        HeaderFormat(LongBitFormat previous, int length, long min) {
            BITS = new LongBitFormat(name(), previous, length, min);
        }

        static short getReplication(long header) {
            return (short) REPLICATION.BITS.retrieve(header);
        }

        static long getPreferredBlockSize(long header) {
            return PREFERRED_BLOCK_SIZE.BITS.retrieve(header);
        }

        static byte getStoragePolicyID(long header) {
            return (byte) STORAGE_POLICY_ID.BITS.retrieve(header);
        }

        static long toLong(long preferredBlockSize, long replication,
                           long storagePolicyID) {
            long h = 0;
            h = PREFERRED_BLOCK_SIZE.BITS.combine(preferredBlockSize, h);
            h = REPLICATION.BITS.combine(replication, h);
            h = STORAGE_POLICY_ID.BITS.combine(storagePolicyID, h);
            return h;
        }
    }

    public static void main(String[] args) {

        long blockSize = 512;
        long replication = 3L;
        long storagePolicyID = 2L;
        long combine = HeaderFormat.toLong(blockSize,replication,storagePolicyID);
        System.out.println("block size:         " + HeaderFormat.getPreferredBlockSize(combine));
        System.out.println("replication:        " + HeaderFormat.getReplication(combine));
        System.out.println("storagePolicyID:    " + HeaderFormat.getStoragePolicyID(combine));
    }
}

tolong 方法的返回值也就是我們狀態(tài)存儲的封裝

http://www.cnblogs.com/huzuoliang/p/7095865.html