Java中使用 Long 表示枚举类

在日常的开发过程中,很多时候我们需要枚举类(enum)来表示对象的各种状态,并且每个状态往往会关联到指定的数字,如:

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

或者用枚举类来表示一系列状态的转变关系:

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

那么,如何用最少的存储来实现这类需求,答案很简单,位存储。如 1bit 表示 0,1 两种状态,2bit 表示 00,01,10,11 四种状态,所以我们可以用一个 long 类型(64bit)/int 类型(32bit)存储多种状态,如下图:

位存储示例

但是每新建一个枚举类都需要自己操作 bit

  1. 导致程序不易理解
  2. 容易出错,耗费精力

Hadoop hdfs 的实现中,也遇到类似的问题,它借助于 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));//移动的位数,右移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;
}
}

当然,你也可以实现 IntBigFormat,ShortBitFormat

首先分析该类的构造方法:

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

字段:
NAME:状态名,可自定义

OFFSET:该状态在 long 字节中的偏移

LENGTH:用多少位存储该状态关联的数字

MIN:该状态关联的最小值

MAX:该状态关联的最大值

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

类方法:
retrieve(long record):获得该状态关联的数字

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 方法的返回值也就是我们状态存储的封装

Java中使用 Long 表示枚举类的更多相关文章

  1. Java中的集合和常用类

    Java中的常用类: ▪ Object类 ▪ Math类 ▪ String类和StringBuffer类(字符串) ▪ 8种基本类型所对应的包装类 ▪ java.util包中的类——Date类 Obj ...

  2. Java中是否可以调用一个类中的main方法?

    前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...

  3. Java中必须了解的常用类

    1.Java的包装类 基本数据类型我们都很熟悉,例如:int.float.double.boolean.char等,基本数据类型不具备对象的特征,不能调用方法,一般能实现的功能比较简单,为了让基本数据 ...

  4. java中常用的包、类、以及包中常用的类、方法、属性----sql和text\swing

    java中常用的包.类.以及包中常用的类.方法.属性 常用的包 java.io.*; java.util.*; java.lang.*; java.sql.*; java.text.*; java.a ...

  5. JAVA中的集合容器操作类

    目录 JAVA中的集合容器操作类 List集合 ArrayList的操作方法说明 LinkedList Stack Set Map Queue 总结 JAVA中的集合容器操作类 Java容器类库总共分 ...

  6. Java中各种集合(字符串类)的线程安全性!!!

    Java中各种集合(字符串类)的线程安全性!!! 一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读 ...

  7. JAVA基础——Java 中必须了解的常用类

    Java中必须了解的常用类 一.包装类 相信各位小伙伴们对基本数据类型都非常熟悉,例如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性的,比如基本类型不 ...

  8. 讲说问题:|和||的区别以及&和&&的区别。2、Java中的数据类型分几类?基本数据类型有哪些?

    |和||的区别以及&和&&的区别. |或 为或运算 判断为逻辑或 || 为短路或 只有逻辑判断 当左侧为真不再继续判断 &与 为与运算 判断为逻辑与 && ...

  9. java中的强大的枚举(基本没人用)

    枚举的概念和多例设计模式相似,多例设计模式详见:多例设计模式代码模型 范例:简单枚举类 通过emu关键字定义一个枚举 package com.java.demo; enum Color{ RED,BL ...

随机推荐

  1. TDE: Transparent Data Encryption brief introduction

    1. What is TDE? Briefly speaking, TDE is used to encrypted data. 2. The benifits: Belows are come fr ...

  2. C#中设置TextBox控件中仅可以输入数字且设置上限

    首先设置只可以输入数字: 首先设置TextBox控件的KeyPress事件:当用户按下的键盘的键不在数字位的话,就禁止输入 private void textBox1_KeyPress(object ...

  3. 2、Java应用中常见的JDBC连接字符串(SQLite、MySQL、Oracle、Sybase、SQLServer、DB2)

    2.Java应用中常见的JDBC连接字符串 Java应用中连接数据库是不可或缺的,于是便整理一些可能用到的JDBC的jar包及其相匹配的URL,以备日后查阅. 1)SQLite Class.forNa ...

  4. 关于ubuntu的图标创建以及快捷方式打开

    //这里个人要添加的的为微信小程序开发工具 1:终端命令: sudo gedit /usr/share/applications/MyChat.desktop 2:修改启动器配置如下: [Deskto ...

  5. nrm是什么?以及nrm的安装与命令

    nrm的作用与安装使用 一.nrm是什么? 这是官方的原话: 开发的npm registry 管理工具 nrm, 能够查看和切换当前使用的registry, 最近NPM经常 down 掉, 这个还是很 ...

  6. R语言的导数计算(转)

    转自:http://blog.fens.me/r-math-derivative/ 前言 高等数学是每个大学生都要学习的一门数学基础课,同时也可能是考完试后最容易忘记的一门知识.我在学习高数的时候绞尽 ...

  7. Docker - 运行 containers 使用在 swarm 模式下创建的 overlay 模式的 network

    前言 在Docker engine v1.12, 使用Swarm可以方便的创建overlay模式的网络,但是它只能被swarm下面的service所使用的,相对于container,这个网络是完全隔离 ...

  8. 前端向后台的华丽转身 — PHP入门篇

    三个月就这么悄悄溜走了,本K对于前端虽然有了一定的认识,但对一些方面还是处于一种比较萌币的状态,就在这种萌币状态下,本K又跟着大神浩开始了后台语言-PHP语言的学习.PHP的学习对于学过其他语言的人来 ...

  9. Spring框架之IOC(控制反转)

    [TOC] 第一章Spring框架简介 IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合.所以,简单来说,Spring是一个轻量级的控制反转(IoC)和面向 ...

  10. testlink(以及服务器)问题定位思路

    testlink又炸了,记录下问题定位思路: 1.翻阅logs: tail -100f ***.log 2.将关键字百度: 但是狗日的网上一般不会告诉我们这修改的文件在哪(上下图无关联,因为图是后面随 ...