用一个int值实现多选(二进制、效率)

  • Post author:
  • Post category:其他


今天仔细了解了下温少的fastjson源码,发现真的是当之无愧的java中最快的json解析库!也发现了一种有趣的算法(当然fastjson中还有TheadLocal缓存、对象路径化、解决互相引用死循环等值得我们深入学习),在fastjson中应用场景是配置序列化json和解析json的可变配置中,他只用了两个int变量来配置(通常我会用List或者Map),先看我模仿他的实现代码先(最后会简要说明),我应用的场景是:高中考试的多选题


实现枚举

package here.wait.go.test.choosed;

/**
 * 多选枚举
 * 
 * @author Wait
 * @date 2013年12月20日 
 * @time 下午10:40:22
 * @email here.wait.go@gmail.com
 * @version 1.0
 */
public enum MultipleChoiceEnum
{
	A, B, C, D;
	private final int mask;
	private  MultipleChoiceEnum()
	{
		mask = 1<<ordinal();
	}
	
	public final int getMask()
	{
		return mask;
	}
	
	/**
	 * 判断是否已经选择
	 * 
	 * @param multipleChoices
	 * @param multipleChoiceEnum
	 * @return
	 */
	public static boolean isChoosed(int multipleChoices, MultipleChoiceEnum multipleChoiceEnum)
	{
		return 0 != (multipleChoices & multipleChoiceEnum.getMask());
	}
}


测试类

package here.wait.go.test.choosed;

import org.junit.Assert;
import org.junit.Test;

/**
 * 模拟多选情况
 * 
 * 选择了A
 * multipleChoice |= MultipleChoiceEnum.A.getMask();
 * 
 * 取消选择A
 * multipleChoice &= ~MultipleChoiceEnum.A.getMask();
 * 
 * @author Wait
 * @date 2013年12月20日 
 * @time 下午10:48:33
 * @email here.wait.go@gmail.com
 * @version 1.0
 */
public class MultipleChoiceTest
{
	@Test
	public void test()
	{
		int multipleChoices = 0;
		//选择了A
		multipleChoices |= MultipleChoiceEnum.A.getMask();
		//选择了B
		multipleChoices |= MultipleChoiceEnum.B.getMask();
		//选择C
		multipleChoices |= MultipleChoiceEnum.C.getMask();
		//突然看同桌不爽,把已选的C去掉
		multipleChoices &= ~MultipleChoiceEnum.C.getMask();
		
		
		Assert.assertEquals(true, MultipleChoiceEnum.isChoosed(multipleChoices, MultipleChoiceEnum.A));
		Assert.assertEquals(true, MultipleChoiceEnum.isChoosed(multipleChoices, MultipleChoiceEnum.B));
		Assert.assertEquals(false, MultipleChoiceEnum.isChoosed(multipleChoices, MultipleChoiceEnum.C));
		Assert.assertEquals(false, MultipleChoiceEnum.isChoosed(multipleChoices, MultipleChoiceEnum.D));
	}
	
}


说明

如上场景有A、B、C、D四个选项

调用方法                    式子                  二进制

A.getMark()              1<<0                       1

B.getMark()              1<<1                     10

C.getMark()              1<<2                    100

D.getMark()              1<<3                   1000

选上是用运算符|(


(有1就1)运算规则:参与运算的二进制数字,低位对齐,高位不足的补零,对应的二进制位有一个为1则结果为1,否则为0。



全部选上是1111,所以每个选项占一位


去掉选项是&=~(



&


位与运算符(


都1才1


)运算规则:参与运算的二进制数字,低位对齐,高位不足的补零,对应的二进制位,都是1的为1,否则为0。



例如去掉B选项:1111&=~10->1111&=1101->1101


最后怎么知道那个选项被选上了,考试要改试卷了!

正确答案是A、C、D

程序怎么判断呢?是这样的

1101&1(A) !=0 ->  true

1101&100(C)!=0 -> true

1101&1000(D)!=0 -> true

恭喜全对了!


优越性

1、比List或者Array的穷举效率要高

2、比使用Map的查表方式更省内存空间


局限性

1、因为是使用二进制的,所以int类型最多只能有32个选项;

2、代码可读性低



版权声明:本文为ze773108248原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。