这个概念是在 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[] 去接收数据?

那么用位有什么好处呢?

  1. void array(NORTH | SOUTH | SOUTH_EAST)

在方法的调用上 可以采用这种直观易懂且计算速度快的方式, 而在传入值 不难发现 最终只有一个值:

  1. 1000 0011

这一个数值即表示了包含了相应的三种状态.而这就是 java中 位域的使用方式.那么进一步来看, 当我们不再满足 8位 甚至需要更多种状态值的时候 可以切换到 int long 甚至于 bitmap. 接收无限位。

但仅仅是位域这种表示 我们仅仅支持 64种以下的状态类型, 因为 java种最长的基本类型 也就只有64位了。

那么继续来看看这种位域有什么缺陷呢?

使用int 类型 或 long类型, 没有办法加入一些自定义的东西, 通常情况下 在这种地方使用枚举是更好地选择。

否则的话所有的地方依然要使用 switch判断的方式, 另外由于 int定义为 static final 时 本身就是编译时常量,

如果有人依赖他, 将来即使这里的数值更新了, 比如删掉两三个, 即使不重新编译, 对方的class文件依然不会出错。 但事实上, 出错是一种必然。

就上面的例子来说, 我们想要返回所有的String 该怎么办?必然是 switch case return "南" 类似的方式.

那么切换成枚举类型呢?

  1. public enum EnumDirection {
  2. NORTH("north"), EAST("east"), SOUTH("south"), WEST("south");
  3. private final String name;
  4. private EnumDirection(String name) {
  5. this.name = name;
  6. }
  7. public String getName() {
  8. return this.name;
  9. }
  10. }

枚举类型的好处,不再赘述。

那与今天的主题, 位域有什么关系呢?我们知道,位域的优点 占用内存小, 表示方便, 传递值方便, 性能高.EnumSet, 让我抄一段描述:

这个类实现Set接口,提供了丰富的功能,类型安全性,以及可以从任何其他Set实现中得到的互用性。但是在内部具体的实现上,每个EnumSet内容都表示为位矢量。如果底层的枚举类型有64个或者更少的元素——大多数如此。整个EnumSet就用单个long来表示,因此它的性能比的上位域的性能。批处理,如removeAll和retainAll,都是利用位算法来实现的。就像手工替代位域实现得那样。

是的, 是位运算.

就看一段代码:

  1. 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 的集合, 如:

  1. EnumSet<EnumDirection> enumSet = EnumSet.of(EnumDirection.EAST,EnumDirection.NORTH);

不难获知 enumSet 的 elements值为 0000 0011 当然 这里是 long类型, 我只写了最后8位, 而

0000 0011 & 0000 1000 必然是等于 0的 因此 contains 返回false.

这是极其高效的方式. 而目的也正在于解决 int型 位域的种种弊端.

EnumSet的更多相关文章

  1. 计算机程序的思维逻辑 (51) - 剖析EnumSet

    上节介绍了EnumMap,本节介绍同样针对枚举类型的Set接口的实现类EnumSet.与EnumMap类似,之所以会有一个专门的针对枚举类型的实现类,主要是因为它可以非常高效的实现Set接口. 之前介 ...

  2. 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 ...

  3. 第32条:用EnumSet代替位域

    如果一个枚举类型的元素主要用在集合中,一般使用int枚举模式,将2的不同倍数赋予每个常量: public class Text { public static final int STYLE_BOLD ...

  4. Java集合概述、Set集合(HashSet类、LinkedHashSet类、TreeSet类、EnumSet类)

    Java集合概述.Set集合(HashSet类.LinkedHashSet类.TreeSet类.EnumSet类) 1.Java集合概述1)数组可以保存多个对象,但数组长度不可变,一旦在初始化数组时指 ...

  5. Java集合框架(二)—— HashSet、LinkedHashSet、TreeSet和EnumSet

    Set接口 前面已经简绍过Set集合,它类似于一个罐子,一旦把对象'丢进'Set集合,集合里多个对象之间没有明显的顺序.Set集合与Collection基本上完全一样,它没有提供任何额外的方法. Se ...

  6. Java编程的逻辑 (51) - 剖析EnumSet

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  7. effective java——32用EnumSet代替位域

    什么是位域?为什么用到它?先来看一个例子: public class Test { public static final byte STYLE_BOLD = 1<<0; // 1 pub ...

  8. Java笔记(九)EnumMap & EnumSet

    EnumMap & EnumSet 一.EnumMap 一)基本用法 public static Map<Size, Integer> countBySize(List<Cl ...

  9. Effective Java 第三版——36. 使用EnumSet替代位属性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  10. 关于枚举,enum、Enum、EnumSet、RegularEnumSet、JumboEnumSet

    Apache Commons Lang. 在版本3中,enum相关的工具就留下EnumUtils. 首先, 所有enum,都默认实现了抽象类 java.lang.Enum .所以,所有enum都具备E ...

随机推荐

  1. 假期学习【四】RDD编程实验一

    1.今天把Spark编程第三个实验的Scala独立程序编程写完了.使用 sbt 打包 Scala 程序,然后提交到Spark运行. 2.完成了实验四的第一项 (1)该系总共有多少学生:   map(t ...

  2. javax.naming.NameNotFoundException: Name jdbc is not bound in this Context

    这个错误的原因是没有项目使用到了Tomcat中配置的数据源(但是你本地没有配置),关于什么是JNDI看这篇文章就够了® 今天导入一个项目(比较老的),在本地运行时报错: Cannot resolve ...

  3. php单例模式封装数据库操作类增删改查

    <?php//三私一公 单例class Db{ //数据库连接对象 private static $instance; private static $table_name; private $ ...

  4. 常用UrlEncode编码结果

    空格 ! # $ % + @ : = ? %20 %21 %23 %24 %25 %2B %40 %3A %3D %3F

  5. 苹果cms10 官方QQ微信防红防封代码

     代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  6. oneshot和周期性shot

    计数器的使用,oneshot:时刻. 有误差,日.每一些间隔可以产生周期性shot(多个持续性时刻)

  7. Microsonf visual c++ 14+ 离线内网安装

    内网离线安装方法:先下载官方的visualcppbuildtools: <br  href=http://go.microsoft.com/fwlink/?LinkId=691126 >& ...

  8. HTML 5的革新——语义化标签(一)

    HTML 5的革新之一:语义化标签一节元素标签. 在HTML 5出来之前,我们用div来表示页面章节,但是这些div都没有实际意义.(即使我们用css样式的id和class形容这块内容的意义).这些标 ...

  9. JavaScript HTML DOM 关系层级(父子兄弟姐妹关系)

    通过 HTML DOM,您能够使用节点关系来导航节点树. DOM 节点 根据 W3C HTML DOM 标准,HTML 文档中的所有事物都是节点: 整个文档是文档节点 每个 HTML 元素是元素节点 ...

  10. Redis09——事务(悲观锁、乐观锁)

    事务 定义: Redis事务是一个单独的隔离操作 ①事务中所有的命令都会被序列化.按照顺序执行 ②事务在执行过程中不会被其他客户端发送来的命令请求打断 作用: 串联多个命令防止别的命令插队 multi ...