简单了解Java位域的一些知识

这个概念是在 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型 位域的种种弊端.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java Spring boot 2.0 跨域问题的解决

    跨域 一个资源会发起一个跨域HTTP请求(Cross-site HTTP request), 当它请求的一个资源是从一个与它本身提供的第一个资源的不同的域名时 . 比如说,域名A(http://domaina.example)的某 Web 应用程序中通过标签引入了域名B(http://domainb.foo)站点的某图片资源(http://domainb.foo/image.jpg),域名A的那 Web 应用就会导致浏览器发起一个跨站 HTTP 请求.在当今的 Web 开发中,使用跨站 HTTP

  • JAVA使用Ldap操作AD域的方法示例

    项目上遇到的需要在集成 操作域用户的信息的功能,第一次接触ad域,因为不了解而且网上其他介绍不明确,比较费时,这里记录下. 说明: (1). 特别注意:Java操作查询域用户信息获取到的数据和域管理员在电脑上操作查询的数据可能会存在差异(同一个意思的表示字段,两者可能不同). (2). 连接ad域有两个地址: ldap://XXXXX.com:389 和 ldap://XXXXX.com:636(SSL). (3). 端口389用于一般的连接,例如登录,查询等非密码操作,端口636安全性较高,用

  • Java微信公众平台之获取地理位置

    本部分需要用到微信的JS-SDK,微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用微信分享.扫一扫.卡券.支付等微信特有的能力,为微信用户提供更优质的网页体验. 官方文档 一.JS-SDK引入 1.先登录微信公众平台进入"公众号设置"的"功能设置"里填写"JS接口安全域名",和网页授权一样只是个域名. 2

  • java实现在pdf模板的指定位置插入图片

    本文实例为大家分享了java在pdf模板的指定位置插入图片的具体代码,供大家参考,具体内容如下 java操作pdf有个非常好用的库itextpdf,maven: <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.6</version> </dependency> <!--

  • Java中EnumSet代替位域代码详解

    本文研究的主要是Java中EnumSet代替位域的相关内容,具体介绍如下. 读书笔记<Effective Java 中文版 第2版> 位域表示法允许利用位操作,有效地执行先 union(联合)和 intersection(交集)这样的集合操作.但是位域有着int枚举常亮的所有缺点,甚至更多.当位域一数字形式打印时,翻译位域比翻译简单的int枚举常量要困难得多.甚至,要遍历位域表示的所有元素都没有很容易的方法. //Bit field enumeration constant - OBSOLET

  • java实现简易局域网聊天功能

    本文实例为大家分享了java使用UDP模式编写聊天程序的具体代码,供大家参考,具体内容如下 Java代码: /* 使用UDP模式,编写一个聊天程序 有发送和接收数据2部分, 一个线程接收,一个线程发送 由于发送和接收动作是不一致的,所以要使用2个run方法 而且这两个方法要封装到不同的类中 本程序忽略了部分异常的处理,也未加入UI组件 这样比较简洁 发送端口9998 接受端口9999 用的是局域网广播地址,所以自己发的消息自己也收到了 [示例]:简易控制台聊天程序 */ import java.

  • 简单了解Java位域的一些知识

    这个概念是在 Effective Java中了解到的, 可以通过EnumSet来代替位域这种方式表达.并不是很常见的概念, 因此记录下.如果在这之前恰好了解过 bitmap这种数据结构就更好了.不了解也没有关系. bitmap 就是用bit的每一位来代表一个特殊的状态值,或者说标签属性等等.举例来说, 8位的数值, 用 0000 0001 代表 北, 0000 0010 代表南, 0000 0100 代表西 依次类推. 那么当我们拿到一串bit, 如:0100 0000 自然可以去对应的映射关系

  • 简单了解JAVA内存区域效果知识

    这篇文章主要介绍了简单了解JAVA内存区域效果知识,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JAVA内存区域介绍 程序计数器: 线程私有,很小的内存空间,可以看做是当前线程所执行的字节码的行号指示器: 每个线程都有一个独立的程序计数器,各个线程之间的计数器相互不影响,独立存储: 如果线程执行的是Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址,如果是一个Native方法,那么这个计数器的值则为undefined: 该内存

  • JNI实现最简单的JAVA调用C/C++代码

    JNI,是Java Native Interface的简称,中文是"Java本地调用".通过这种技术可以做到以下两点: Java程序中的函数可以调用Native语言写的函数,Native一般指的是C/C++编写的函数. Native程序中的函数可以调用Java层的函数,也就是说在C/C++程序中可以调用Java的函数. 本篇博客带给童鞋们以下内容,学习内容来自(传智播客),经由小巫总结整理: javah工具的用法 按照C/C++头文件来编写C/C++源文件 将C/C++源文件编译成动态

  • Java多线程的其他知识_动力节点Java学院整理

    一.线程组 /** * A thread group represents a set of threads. In addition, a thread * group can also include other thread groups. The thread groups form * a tree in which every thread group except the initial thread group * has a parent. * <p> * A thread

  • 简单介绍Java垃圾回收机制

    Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Java深受大家欢迎的众多特性之一,能够帮助程序员更好地编写Java程序. 这篇教程是系列第一部分.首先会解释基本的术语,比如JDK.JVM.JRE和HotSpotVM.接着会介绍JVM结构和Java堆内存结构.理解这些基础对于理解后面的垃圾回收知识很重要. Java关键术语 JavaAPI:一系列帮助开发者创建Java应用程序的封装好的库. Java开发工具包(JDK):一

  • java基面试础知识详解

    面向对象的三大特性 1)封装 就是把同一类事物的属性和方法归到同一个类中,方便使用 防止该类的代码和数据被外部类定义的代码随意访问 要访问该类的数据和代码必须通过严格的方法控制 封装的主要功能在于我们能修改自己的实现代码,而不用修改哪些调用程序的代码片段. 优点:减少耦合,类内部自由修改,可以对类成员变量进行更精确的控制,隐藏信息.实现细节. 最佳实践: 为了实现良好的封装,通常将类的成员变量声明为private ,通过public的set和get方法完成对属性的操作 2)继承 继承就是子类继承

  • 简单了解Spring Cloud Alibaba相关知识

    这篇文章主要介绍了简单了解Spring Cloud Alibaba相关知识,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 官方github地址 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案.此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务. 主要功能 服务限流降级:默认支持 WebServlet.WebFlux, OpenFeign

  • Java虚拟机执行引擎知识总结

    执行引擎 也只有几个概念, JVM方法调用和执行的基础数据结构是 栈帧, 是内存区域中 虚拟机栈中的栈元素, 每一个方法的执行就对应着一个栈帧在虚拟机栈中出栈入栈的过程. 栈帧:则是包含有局部变量表, 操作数栈, 动态连接, 方法返回地址, 附加信息. 1 局部变量表: 存储单位是 slot, 一个slot占据32位, 对于64位的数据类型, 则是分配连续两个slot空间. 而对于一个非静态方法而言, 有一个隐藏参数, 为 this, 而在局部变量表中的变量存储顺序则是 this -> 方法参数

  • JAVA内存空间相关知识汇总

    Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java在内存分配方面的知识.一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存放用new产生的数据 ◆静态域:存放在对象中用static定义的静态成员 ◆常量池:存放常量 ◆非RAM存储:硬盘等永久存储空间 Java内存

  • Java并发容器相关知识总结

    一.并发容器 1.1 JDK 提供的并发容器总结 JDK 提供的这些容器大部分在java.util.concurrent包中. ConcurrentHashMap: 线程安全的 HashMap CopyOnWriteArrayList: 线程安全的 List,在读多写少的场合性能非常好,远远好于 Vector. ConcurrentLinkedQueue: 高效的并发队列,使用链表实现.可以看做一个线程安全的 LinkedList,这是一个非阻塞队列. BlockingQueue: 这是一个接口

随机推荐