背景介绍
位操作,想必大家在学习计算机基础知识的时候都有所接触过,但是日常却老是想不起来使用,今天就提供一个使用的思路.
我们经常需要表示多个bool变量,比如:当一个人秃头并且背着双肩包,穿着格子衬衫,我们就叫他程序员,羞辱一下他.
那么正常的情况下,我们需要些三个if/else来实现这个操作:
1 2 3 4 5 6 7
| if(tutou){ if(hasAshuangjianbao){ if(inTShirt){ System.out.println("this is a programer"); } } }
|
当条件逐渐增多,这样的代码会越来越难看.因此我们考虑一下使用bit.
int表示bool
一个int在java中是4个字节,也就是工32bits.每一个bit有0,1两种状态,那么就可以表示true/false
两种状态.
那么我们设计一下:
- 第一位表示是否是秃头,为1的时候为真.换算成int就是0代表不秃头,1代表秃头.
- 第二位表示是否背着双肩包.为
10
,11
的时候表示有,01
,00
表示没有.
- 第三位表示是否穿子格子衬衫,1表示有,对应的序列为
110,111,101,100
四种,0表示没有010,011,001,000
表示没有.
发现规律了吧,当我们要表示三个布尔值时,总共有8中可能的序列,正好对应了三种状态的排列组合,2 * 2 * 2 = 8
.
我们想表示一个人,没有秃头,穿着格子衬衫,背着双肩包
使用的序列是110
,对应int中的6
.
或 |
通过或我们可以拿到多个状态的并集.比如 1,2,4
进行或操作之后,拿到的是111
也就是7
,所以7可以代表三个状态全部为真.
与 &
通过 & 操作可以拿到给定结果(|操作拿到的)和给定状态(你选一个咯)的并集.比如上面拿到的7
,你想验证是否满足秃头(1)
,那么执行7 & 1
拿到的结果如果为1
即满足.
即result & tag = = tag
.
原理清楚了我们看一下代码实现.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import mian.AbstractMain;
public class BitIntTest extends AbstractMain {
public static void main(String[] args) { new BitIntTest().parseArgsAndRun(args); }
@Override public void run() { int flag = 0;
flag |= 1; System.out.println(Flag.isSet(flag, Flag.TU_TOU)); System.out.println(Flag.isSet(flag, Flag.INAPACKAGE));
flag |= 2; System.out.println(Flag.isSet(flag, Flag.INAPACKAGE)); System.out.println(Flag.isSet(flag, Flag.TU_TOU));
System.out.println(Flag.isAllSet(flag,Flag.TU_TOU,Flag.INAPACKAGE));
flag |= 3; System.out.println(Flag.isAllSet(flag, Flag.INAPACKAGE, Flag.TU_TOU, Flag.INTSHIRT));
}
public static final class Flag { static int TU_TOU = 1; static int INAPACKAGE = 2; static int INTSHIRT = 4;
public static boolean isSet(int flag, int tag) { return (flag & tag) == tag; }
public static boolean isAllSet(int flag, int... tags) { int tag = 0; for (int i : tags) { tag |= i; } return (flag & tag) == tag; } } }
|
比较核心的就是Flag
内部类,我们在其中实现了两个方法.
- isSet: 验证是否满足给定的tag.比如
6 & 1
,那就是不满足.5 & 1
就是满足.
- isAllSet. 验证是否满足给定的所有条件,这里用了一个可变参数的方法.首先对所有给定的tag相|,然后重复1中的操作.
JDK中的实现
在java.lang.reflect
包中,有一个Modifier
类.使用的就是这个思想.
这个类位于反射包中,主要是用于,在反射过程中,拿到的方法,变量等等,然后通过这个类来识别他们的修饰符,public/static/native
等等.
因为这些修饰符可能是冲突的,可能是可以并存的,因此使用这种实现方法.
下面是类中对于修饰符的常量定义.(使用16进制是为了好看.看起来更加的直观).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public static final int PUBLIC = 0x00000001;
public static final int PRIVATE = 0x00000002;
public static final int PROTECTED = 0x00000004;
public static final int STATIC = 0x00000008;
public static final int FINAL = 0x00000010;
public static final int SYNCHRONIZED = 0x00000020;
public static final int VOLATILE = 0x00000040;
public static final int TRANSIENT = 0x00000080;
public static final int NATIVE = 0x00000100;
public static final int INTERFACE = 0x00000200;
public static final int ABSTRACT = 0x00000400;
public static final int STRICT = 0x00000800;
|
写一段代码测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import java.lang.reflect.Field; import java.lang.reflect.Modifier;
public class ModifiersTest {
private static int age = 999;
public static void main(String[] args) throws NoSuchFieldException { Field myAge = ModifiersTest.class.getDeclaredField("age"); int ageMod = myAge.getModifiers();
System.out.println("打印十进制:" + ageMod); System.out.println("是否是private:" + Modifier.isPrivate(age)); System.out.println("是否是final:" + Modifier.isFinal(age));
} }
|
打印结果为:
1 2 3
| 打印十进制:10 是否是private:true 是否是final:false
|
原理和上面自己实现的类似,这里不再赘述.有兴趣的胖友可以查看JDK源码学习一下,这个类比较简单.
ChangeLog
2019-05-09 完成
以上皆为个人所思所得,如有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文链接。
联系邮箱:huyanshi2580@gmail.com
更多学习笔记见个人博客——>呼延十