zoukankan      html  css  js  c++  java
  • 如何使用EnumSet实现基于bit field的enum set?

    如果我们在使用有一个枚举类型时,每次会用到其一项或多项(也就是enum set)时,会怎么做呢?

    在Java没有引入EnumSet之前,有一种叫int enum pattern(assigning a different power of 2 to each constant)的做法,例如一个字体的style的枚举会写成

    public static final int STYLE_BOLD = 1 << 0; // 1
    public static final int STYLE_ITALIC = 1 << 1; // 2
    public static final int STYLE_UNDERLINE = 1 << 2; // 4
    public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8

    在使用的时候,我们用按位与(|),就可以combine several constants into a set

    text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

    不过这种做法已经是obsolete了,可以用EnumSet来替代,and it is more concise and flexible,至于效率方面,完全没有下降,因为EnumSet内部实现也是用bitwise的。

    那么上面的例子就可以写成这样

    // EnumSet - a modern replacement for bit fields
    public class Text {
    public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }
    // Any Set could be passed in, but EnumSet is clearly best
    text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
    }


    如果我们要把这个EnumSet存储到数据库怎么办呢?其实这样的case还是挺多的,我们经常会有flag这样的column,来表示(is or is not),如果这个flag只存储一个(1 或 0 ) 虽然看起来很简单,但是很浪费而且没有扩展性,overtime,新需求也许需要个flagB,  那么你又要加一个新column,flagC,flagD.... frustrated

    如果我们把EnumSet直接存到数据库,上面的问题就可以解决了,怎么存呢?看看EnumSet的源码,就知道其实它是用一个long elements来represent 这个set的, 那么我们需要写个工具类能在long和EnumSet之间做转化, 这样就可以存取数据库了。

    long转EnumSet

    	/**
    	 * Create an enum set by parsing the specified value based on the specified enum type
    	 * 
    	 * @param originalEnumType the class object of the enum type
    	 * @param elements The 2^k bit indicates the presence of the element in this set
    	 * @return
    	 */
    	public static <T extends Enum<T>> EnumSet<T> parseEnumSet(Class<T> originalEnumType, long elements){
    		EnumSet<T> resultEnumSet = EnumSet.allOf(originalEnumType);
    		for (T element : resultEnumSet){
    			if ((elements & (1L << element.ordinal())) == 0)//Check if it is 1 at bit 2^K
    				resultEnumSet.remove(element);
    		}
    		return resultEnumSet;		
    	}
    

    EnumSet转long

    	/**
    	 * Calculate the elements' long value from a given enum set
    	 * 
    	 * @param originalEnumSet the given enum set
    	 * @return long value of elements in this set
    	 */
    	public static <T extends Enum<T>> long getElementsValue(EnumSet<T> originalEnumSet){		
    		if (originalEnumSet == null)
    			return 0;
    		
    		long elements = 0;
    		for (T element : originalEnumSet){
    			elements |= (1L << element.ordinal());
    		}
    		return elements;
    	}

    使用

    		//Calculate the long value before storing in DB
    		System.out.println(EnumSetUtil.getElementsValue(EnumSet.of(Style.BOLD, Style.TEST, Style.UNDERLINE)));
    		
    		//Parse the enum set from long value after fetching from DB
    		System.out.println(EnumSetUtil.parseEnumSet(Style.class, 10));



    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    类(抽象类与非抽象类)和接口
    Arduino学习——u8glib提供的字体样式
    Arduino学习——u8glib库资料整理
    Arduino学习——Arduino main 函数
    全局变量的初始化
    nmake学习笔记2
    Big Endian与Litter Endian
    nmake学习笔记
    重载操作符
    offsetof的意义
  • 原文地址:https://www.cnblogs.com/significantfrank/p/4875852.html
Copyright © 2011-2022 走看看