枚举——用EnumSet代替位域

文章介绍了Java中使用位域(bitfield)进行状态表示和组合,通过位运算实现高效内存利用。然而,位域在调试时不够直观,为此提出使用EnumSet结合枚举类型,既能保持位运算的性能优势,又能提供更友好的编程体验。示例代码展示了如何用EnumSet替换位域实现。
摘要由CSDN通过智能技术生成

在java中,我们经常会定义一些常量值,来表示一些状态,每个常量值代表的意思都不一样,而且通过位运算 | ,可以将不同的样式合并到一个值中表示,这叫做位域(bit field)

public class Text {
    private static final int STYLE_BOLD = 1<<0;            //1  样式--粗体
    private static final int STYLE_ITALIC = 1<<1;          //2  样式--斜体
    private static final int STYLE_UNDERLINE = 1<<2;       //4  样式--下划线
    private static final int STYLE_STRIKETHROUGH = 1<<3;   //8  样式--删除线

    public static final byte[] arr = {STYLE_BOLD, STYLE_ITALIC, STYLE_UNDERLINE, STYLE_STRIKETHROUGH};

    //将样式分解之后得出样式的组合情况
    public static void applyStyles(int style){
        for (int i = 0, count = arr.length; i < count; i++){
            int value = arr[i] & style;
            if(value != 0){
                System.out.println(value);
            }
        }
    }

    public static void main(String[] args) {
        //我们传入5,代表粗体+下划线样式
        Text.applyStyles(5);
    }
}

猛一看,可能有点懵。为什么要这么写,我举个最简单的例子。

大家都做过多选题,比如有abcd四个选项,在上述例子中,

STYLE_BOLD 代表 a

STYLE_ITALIC 代表 b

STYLE_UNDERLINE 代表 c

STYLE_STRIKETHROUGH 代表 d

假如有个题的答案是 ab,那么我们就需要 int value = Text.STYLE_BOLD | Text.STYLE_ITALIC; 来表示;如果是acd, 那么就是 int value = Text.STYLE_BOLD | Text.STYLE_UNDERLINE | Text.STYLE_STRIKETHROUGH; 可能有疑问,问什么可以用这样方法标识值呢,为什么非得是 1、2、4、8 呢,我直接用0、1、2、3 来标识可以吗?

我们知道,位运算是把int值转换为二进制,然后计算的, int value = Text.STYLE_BOLD | Text.STYLE_ITALIC 值为 1+2=3, int value = Text.STYLE_BOLD |Text.STYLE_UNDERLINE | Text.STYLE_STRIKETHROUGH; 值为1+4+8=13;通过二进制可以发现,他们的值的组成都是单一的, 例如 3 只能 是 1 和 2 组成, 13只能是1和4和8组成,只要能看懂二进制都能明白这个道理,不懂的需要先熟悉一下二进制。二进制本身就是以2为基础,每次都乘以2获取值位移,所以这种情况用位移能标识值的唯一的分解法。 如果 我们选取了 0、1、2、3 来标识abcd这四个值,那么不定项选择中,如果答案为bc,那么值是 1+2=3,但问题来了,d选项的值也是3,那么3对应的就是两种可能,bc或者d,因为是不定项选择,我们也没法确定是哪个,所以不能随意标识值,只能选择那些组合出来的值只能被分解成唯一的几个子值,位移就是其中一个完美的选择。饶了这么多,只想解释一下上面那个方法的使用场景,有使用场景利于加深理解和记忆。

上述的方法中,我们会调用applyStyles(int styles)方法,

比如 new Text().applyStyles(Text.STYLE_BOLD | Text.STYLE_ITALIC); 我们在applyStyles(int styles) 方法中,通过 & 运算,分解出每个值,然后做相应的操作


位域的优缺点都非常明显,优点是利用了位运算,效率很高,节省内存。缺点是对程序员调试非常不友好,其输出只有数字,甚至比简单的 int 枚举形式更困难,需要人肉执行运算

幸运的是,java 中有 enumSet ,不仅保留了位域的位运算优点,且代码格式对程序员也非常友好。以上的代码可以改为

public class EnumSetTest {
    public enum Style {
        BOLD, ITALIC, UNDERLINE, STRIKETHROUGH;
    }
    public static void applyStyles(EnumSet<Style> styles) {
        for(Style style : styles){
//            doSome(style);
        };
    }
    public static void main(String[] args) {
        EnumSet<Style> styles = EnumSet.of(Style.BOLD, Style.UNDERLINE);
        applyStyles(styles);
    }
}

使用 EnumSet ,我们可以得到位域的性能和枚举的方便安全,因此 ,如果需要位域,那么可以考虑使用枚举 + EnumSet 来代替。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值