在日常的開發(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),如下圖:
位存儲示例
但是每新建一個枚舉類都需要自己操作 bit
:
導致程序不易理解
容易出錯,耗費精力
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