Java中使用 Long 表示枚举类
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
:
- 导致程序不易理解
- 容易出错,耗费精力
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 表示枚举类的更多相关文章
- Java中的集合和常用类
Java中的常用类: ▪ Object类 ▪ Math类 ▪ String类和StringBuffer类(字符串) ▪ 8种基本类型所对应的包装类 ▪ java.util包中的类——Date类 Obj ...
- Java中是否可以调用一个类中的main方法?
前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...
- Java中必须了解的常用类
1.Java的包装类 基本数据类型我们都很熟悉,例如:int.float.double.boolean.char等,基本数据类型不具备对象的特征,不能调用方法,一般能实现的功能比较简单,为了让基本数据 ...
- java中常用的包、类、以及包中常用的类、方法、属性----sql和text\swing
java中常用的包.类.以及包中常用的类.方法.属性 常用的包 java.io.*; java.util.*; java.lang.*; java.sql.*; java.text.*; java.a ...
- JAVA中的集合容器操作类
目录 JAVA中的集合容器操作类 List集合 ArrayList的操作方法说明 LinkedList Stack Set Map Queue 总结 JAVA中的集合容器操作类 Java容器类库总共分 ...
- Java中各种集合(字符串类)的线程安全性!!!
Java中各种集合(字符串类)的线程安全性!!! 一.概念: 线程安全:就是当多线程访问时,采用了加锁的机制:即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读 ...
- JAVA基础——Java 中必须了解的常用类
Java中必须了解的常用类 一.包装类 相信各位小伙伴们对基本数据类型都非常熟悉,例如 int.float.double.boolean.char 等.基本数据类型是不具备对象的特性的,比如基本类型不 ...
- 讲说问题:|和||的区别以及&和&&的区别。2、Java中的数据类型分几类?基本数据类型有哪些?
|和||的区别以及&和&&的区别. |或 为或运算 判断为逻辑或 || 为短路或 只有逻辑判断 当左侧为真不再继续判断 &与 为与运算 判断为逻辑与 && ...
- java中的强大的枚举(基本没人用)
枚举的概念和多例设计模式相似,多例设计模式详见:多例设计模式代码模型 范例:简单枚举类 通过emu关键字定义一个枚举 package com.java.demo; enum Color{ RED,BL ...
随机推荐
- 学习笔记:javascript内置对象:日期对象
2.日期对象的常用函数 2.日期对象的常用函数 Date 对象方法 方法 描述 Date() 返回当日的日期和时间. getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31). ...
- Linux-vim学习入门
1.前言 vi/vim是linux中很重要的文本编辑器.我第一次使用这个编辑器时,很不习惯,甚至都不知道如何移动光标和插入字符.慢慢地经过学习,才知道如何使用vi/vim. vi/vi ...
- MySQL unique 注意
刚才修改表结构: alter table room add CONSTRAINT roomname_unique UNIQUE(roomname); 结果提示如下错误: ERROR : Specifi ...
- sublime比较好用的插件
emmet, markdown preview, package Control, SFTP, Anaconda
- Web攻防系列教程之跨站脚本攻击和防范技巧详解
摘要:XSS跨站脚本攻击一直都被认为是客户端Web安全中最主流的攻击方式.因为Web环境的复杂性以及XSS跨站脚本攻击的多变性,使得该类型攻击很 难彻底解决.那么,XSS跨站脚本攻击具体攻击行为是什么 ...
- 探讨SQL Server并发处理队列数据不阻塞解决方案
前言 之前对于并发这一块确实接触的比较少,自从遇到现在的老大,每写完一块老大都会过目一下然后给出意见,期间确实收获不少,接下来有几篇会来讲解SQL Server中关于并发这一块的内容,有的是总结,有的 ...
- WebApi2 文件图片上传下载
Asp.Net Framework webapi2 文件上传与下载 前端界面采用Ajax的方式执行 一.项目结构 1.App_Start配置了跨域访问,以免请求时候因跨域问题不能提交.具体的跨域配置方 ...
- JavaSE教程-01初识Java
1.计算机的概念 软件+硬件 2.操作系统 Windows.Mac.Linux.Unix等 3.计算机编程语言 计算机语言是一种人与计算机沟通的媒介. 分类: 机器语言:都是基于二进制的方式,由0和1 ...
- 在linux下利用信号量实现一个写者线程多个读者线程
#include<pthread.h> #include<string.h> #include<stdlib.h> #include<stdio.h> ...
- 06.04 html
域名跟ip地址是绑定的看某个网站的ip地址 可以ping网址知道ip地址 最终访问的都是ip地址 每个ip地址都对应了一个空间(一块区域 要用来存储内容)网页访问的原理: 客户端电脑发动请求到服 ...