EnumSet
这个概念是在 Effective Java中了解到的, 可以通过EnumSet来代替位域这种方式表达.并不是很常见的概念, 因此记录下.如果在这之前恰好了解过 bitmap这种数据结构就更好了。不了解也没有关系。
bitmap 就是用bit的每一位来代表一个特殊的状态值,或者说标签属性等等.举例来说, 8位的数值, 用 0000 0001 代表 北, 0000 0010 代表南, 0000 0100 代表西 依次类推.
那么当我们拿到一串bit, 如:0100 0000 自然可以去对应的映射关系表中查找到 究竟是属于哪一种类型, 如果我们想同时传递两个数值呢?
只需要 0000 0011 这样就可以表示 北 南 两个方向了, 当然 至多可以表示 8个方向.
我们来试试这种表示方式:
public class Direction {
public static final short NORTH = 1;
public static final short SOUTH = 1 << 2;
public static final short WEST = 1 << 3;
public static final short EAST = 1 << 4;
public static final short SOUTH_EAST = 1 << 8;
}
在这里我只是简略的定义了其中5中.
那么可能会有一个问题, 既然使用 short来表示, 为什么不用 1 2 3 ... 8 来表示数据呢? 这样我们甚至都不需要2 的 8次方, 只需要 3位就能够表示所有数据了.
但是不妨让我们再来想一想, 在使用 1 ~ 8 的方式中如何同时传入多种状态呢?
在这里是不是必须使用 一个 short[] 去接收数据?
那么用位有什么好处呢?
- void array(NORTH | SOUTH | SOUTH_EAST)
在方法的调用上 可以采用这种直观易懂且计算速度快的方式, 而在传入值 不难发现 最终只有一个值:
- 1000 0011
这一个数值即表示了包含了相应的三种状态.而这就是 java中 位域的使用方式.那么进一步来看, 当我们不再满足 8位 甚至需要更多种状态值的时候 可以切换到 int long 甚至于 bitmap. 接收无限位。
但仅仅是位域这种表示 我们仅仅支持 64种以下的状态类型, 因为 java种最长的基本类型 也就只有64位了。
那么继续来看看这种位域有什么缺陷呢?
使用int 类型 或 long类型, 没有办法加入一些自定义的东西, 通常情况下 在这种地方使用枚举是更好地选择。
否则的话所有的地方依然要使用 switch判断的方式, 另外由于 int定义为 static final 时 本身就是编译时常量,
如果有人依赖他, 将来即使这里的数值更新了, 比如删掉两三个, 即使不重新编译, 对方的class文件依然不会出错。 但事实上, 出错是一种必然。
就上面的例子来说, 我们想要返回所有的String 该怎么办?必然是 switch case return "南" 类似的方式.
那么切换成枚举类型呢?
- public enum EnumDirection {
- NORTH("north"), EAST("east"), SOUTH("south"), WEST("south");
- private final String name;
- private EnumDirection(String name) {
- this.name = name;
- }
- public String getName() {
- return this.name;
- }
- }
枚举类型的好处,不再赘述。
那与今天的主题, 位域有什么关系呢?我们知道,位域的优点 占用内存小, 表示方便, 传递值方便, 性能高.EnumSet, 让我抄一段描述:
这个类实现Set接口,提供了丰富的功能,类型安全性,以及可以从任何其他Set实现中得到的互用性。但是在内部具体的实现上,每个EnumSet内容都表示为位矢量。如果底层的枚举类型有64个或者更少的元素——大多数如此。整个EnumSet就用单个long来表示,因此它的性能比的上位域的性能。批处理,如removeAll和retainAll,都是利用位算法来实现的。就像手工替代位域实现得那样。
是的, 是位运算.
就看一段代码:
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;
}
我们关注到最后一行, 如上述EnumDirection, WEST 的 ordinal() 即是4, 也就意味着 它值在这里被理解为 1 << 4
而通过 elements 传入enumSet 的集合, 如:
- EnumSet<EnumDirection> enumSet = EnumSet.of(EnumDirection.EAST,EnumDirection.NORTH);
不难获知 enumSet 的 elements值为 0000 0011 当然 这里是 long类型, 我只写了最后8位, 而
0000 0011 & 0000 1000 必然是等于 0的 因此 contains 返回false.
这是极其高效的方式. 而目的也正在于解决 int型 位域的种种弊端.
EnumSet的更多相关文章
- 计算机程序的思维逻辑 (51) - 剖析EnumSet
上节介绍了EnumMap,本节介绍同样针对枚举类型的Set接口的实现类EnumSet.与EnumMap类似,之所以会有一个专门的针对枚举类型的实现类,主要是因为它可以非常高效的实现Set接口. 之前介 ...
- Effective Java 32 Use EnumSet instead of bit fields
Bit fields is used for passing around sets of constants. Such as // Bit field enumeration constants ...
- 第32条:用EnumSet代替位域
如果一个枚举类型的元素主要用在集合中,一般使用int枚举模式,将2的不同倍数赋予每个常量: public class Text { public static final int STYLE_BOLD ...
- Java集合概述、Set集合(HashSet类、LinkedHashSet类、TreeSet类、EnumSet类)
Java集合概述.Set集合(HashSet类.LinkedHashSet类.TreeSet类.EnumSet类) 1.Java集合概述1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指 ...
- Java集合框架(二)—— HashSet、LinkedHashSet、TreeSet和EnumSet
Set接口 前面已经简绍过Set集合,它类似于一个罐子,一旦把对象'丢进'Set集合,集合里多个对象之间没有明显的顺序.Set集合与Collection基本上完全一样,它没有提供任何额外的方法. Se ...
- Java编程的逻辑 (51) - 剖析EnumSet
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- effective java——32用EnumSet代替位域
什么是位域?为什么用到它?先来看一个例子: public class Test { public static final byte STYLE_BOLD = 1<<0; // 1 pub ...
- Java笔记(九)EnumMap & EnumSet
EnumMap & EnumSet 一.EnumMap 一)基本用法 public static Map<Size, Integer> countBySize(List<Cl ...
- Effective Java 第三版——36. 使用EnumSet替代位属性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 关于枚举,enum、Enum、EnumSet、RegularEnumSet、JumboEnumSet
Apache Commons Lang. 在版本3中,enum相关的工具就留下EnumUtils. 首先, 所有enum,都默认实现了抽象类 java.lang.Enum .所以,所有enum都具备E ...
随机推荐
- 关于docker容器访问的主机的端口问题
docker容器需要访问主机的,不能使用127.0.0.1,127.0.0.1访问的是docker容器不是主机: docker容器创建时会分配一个主机ip,可在主机使用命令 docker inspec ...
- UTF自动化测试工具
自UFT推出后,QTP慢慢退出历史舞台 UFT测试的基本流程:录制测试脚本—-编辑测试脚本—-调试测试脚本—-运行测试脚本—-分析测试结果 UFT(QTP)介绍 http://blog.csdn. ...
- HDU 4544 湫湫系列故事——消灭兔子 (优先队列)
湫湫减肥 越减越肥! 最近,减肥失败的湫湫为发泄心中郁闷,在玩一个消灭免子的游戏. 游戏规则很简单,用箭杀死免子即可. 箭是一种消耗品,已知有M种不同类型的箭可以选择,并且每种箭都会对兔子 ...
- [国家集训队] 拉拉队排练 - Manacher
用 Manacher 跑出回文串长,注意这里不需要偶数长度所以不需要对串做一些奇怪的处理 然后用前缀和搞一下,计算答案时跑快速幂即可 #include <bits/stdc++.h> us ...
- [十二省联考2019] 异或粽子 - 可持久化Trie,堆
求 \(n\) 元数列的 \(k\) 个不同的子区间使得各个子区间异或和之和最大. Solution (差点又看错题了) 做个前缀和,于是转化成求序列异或和最大的 \(k\) 个数对 建一棵可持久化 ...
- MFC线程间消息传递(转)
原文地址:https://blog.csdn.net/qq_37059136/article/details/84972192
- 二分-G - 4 Values whose Sum is 0
G - 4 Values whose Sum is 0 The SUM problem can be formulated as follows: given four lists A, B, C, ...
- lnmp1.5一键安装包安装lnmpa后,添加站点
lnmp1.5一键安装包安装lnmpa后,添加站点 (1)添加站点 (2)配置apache配置文件 在/usr/local/apache/conf/vhost文件夹下,修改webApp站点配置文件ap ...
- sql server和my sql 命令(语句)的区别,sql server与mysql的比较
sql与mysql的比较 1.连接字符串sql :Initial Catalog(database)=x; --数据库名称 Data Source(source)=x; - ...
- JS高级---案例:验证密码的强度
案例:验证密码的强度 1. 给我密码,我返回对应的级别 2. 每次键盘抬起都要获取文本框中的内容, 验证文本框中有什么东西, 得到一个级别, 然后下面的div显示对应的颜色 <!DOCTYPE ...