Java 位域

Java位域


这个概念是在 Effective Java中了解到的, 能够经过EnumSet来代替位域这种方式表达.
java

并非很常见的概念, 所以记录下.算法

若是在这以前刚好了解过 bitmap这种数据结构就更好了。安全

不了解也没有关系。数据结构

bitmap 就是用bit的每一位来表明一个特殊的状态值, 或者说标签属性等等.性能

举例来讲, 8位的数值, 用 0000 0001 表明 北, 0000 0010 表明南, 0000 0100 表明西 依次类推.this

那么当咱们拿到一串bit, 如:code

0100 0000 天然能够去对应的映射关系表中查找到 到底是属于哪种类型, 若是咱们想同时传递两个数值呢?接口

只须要 0000 0011 这样就能够表示 北 南 两个方向了, 固然 至多能够表示 8个方向.内存

咱们来试试这种表示方式:element

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型 位域的种种弊端.

相关文章
相关标签/搜索