Java中的位掩碼BitMask


JDK源碼的使用

最近在JDK源碼中閑逛,無意中看到了java.lang.reflect.Modifier這個類,這個類很簡單,都是些常量定義和判斷方法,於是扒了扒代碼實現的含義,我們就看個isPublic方法吧:

/**
 * Return {@code true} if the integer argument includes the
 * {@code public} modifier, {@code false} otherwise.
 *
 * @param   mod a set of modifiers
 * @return {@code true} if {@code mod} includes the
 * {@code public} modifier; {@code false} otherwise.
 */
public static boolean isPublic(int mod) {
    return (mod & PUBLIC) != 0;
}
 /**
 * The {@code int} value representing the {@code public}
 * modifier.
 */
public static final int PUBLIC = 0x00000001;
 /**
 * The {@code int} value representing the {@code static}
 * modifier.
 */
public static final int STATIC = 0x00000008;

/**
 * The {@code int} value representing the {@code final}
 * modifier.
 */
public static final int FINAL  = 0x00000010;

我們來看看java.lang.Class類中的幾個方法:

public boolean isAnnotation() {
    return (getModifiers() & ANNOTATION) != 0;
}

public boolean isEnum() {
    // An enum must both directly extend java.lang.Enum and have
    // the ENUM bit set; classes for specialized enum constants
    // don't do the former.
    return (this.getModifiers() & ENUM) != 0 &&
    this.getSuperclass() == java.lang.Enum.class;
}

可以看到Class的getModifier()方法返回的整形值又能判斷當前類是否是Enum,又能判斷是否是Annotation。

Modifier中定義了很多modifier的值,這些值都很有規律,從前往后依次都是2的n次方的16進制表示,也就是二進制的1每次左移的結果。最后的效果就是不同類型的modifier都在二進制形式的值中占一位。比如:

PUBLIC:   0x00000001,二進制:0001
PRIVATE:  0x00000002,二進制:0010
PROTECTED:0x00000004,二進制:0100
STATIC:   0x00000008,二進制:1000

如果想表示一個類既是public又是static的時候,這時候getModifier()方法就會返回1001也就是整形9,而我們可以通過9的二進制表示來做位運算,就是文章開頭的函數:

public static boolean isPublic(int mod) {
    return (mod & PUBLIC) != 0;
}

這時候傳入的mod為9,也就是1001,而public修飾符定義的值為0001,這兩者做與運算的時候返回就是0001,該結果不為0,即當前方式是有public修飾符的。

至此,這種由單個值表示多種狀態的方式就叫做Java中的位掩碼。

日常工作中的使用

例如,在一個系統中,用戶一般有查詢(Select)、新增(Insert)、修改(Update)、刪除(Delete)四種權限,四種權限有多種組合方式,也就是有16中不同的權限狀態(2的4次方)。

一般情況下會想到用四個boolean類型變量來保存:

public class Permission {
	// 是否允許查詢
	private boolean allowSelect;
	// 是否允許新增
	private boolean allowInsert;
	// 是否允許刪除
	private boolean allowDelete;
	// 是否允許更新
	private boolean allowUpdate;
}

但是如果使用位掩碼的話,就可以用和Modifier類相似的方式了(1表示允許,0表示不允許):

public class NewPermission {
    public static final int ALLOW_SELECT = 1 << 0; // 0001
    public static final int ALLOW_INSERT = 1 << 1; // 0010
    public static final int ALLOW_UPDATE = 1 << 2; // 0100
    public static final int ALLOW_DELETE = 1 << 3; // 1000
    	
    // 存儲目前的權限狀態
    private int flag;
    
    // 重新設置權限
    public void setPermission(int permission) {
        flag = permission;
    }
    
    // 添加一項或多項權限,比如當前只有select(0001),增加insert(0010)
    // 0001
    // 0010 |
    // 0011 = 即可以select也可以insert 
    public void enable(int permission) {
        flag |= permission;
    }
    	
    // 刪除一項或多項權限,比如當前可以select、insert(0011),去掉insert()
    // 0010
    // 1101 ~
    // 0011 &
    // 0001 = 即只可以select了
    public void disable(int permission) {
        flag &= ~permission;
    }
    	
    // 是否擁某些權限
    public boolean isAllow(int permission) {
        return (flag & permission) == permission;
    }
    	
    // 是否禁用了某些權限
    public boolean isNotAllow(int permission) {
        return (flag & permission) == 0;
    }
    	
    // 是否僅僅擁有某些權限
    public boolean isOnlyAllow(int permission) {
        return flag == permission;
    }
}

今天分享的就是這樣一個小細節,希望對大家有幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM