前言
如果你不了解位運(yùn)算,那你應(yīng)該要補(bǔ)習(xí)一下功課,這里就不對(duì)位移運(yùn)算做補(bǔ)習(xí),因?yàn)榻裉煊玫降氖桥c、或、非在二進(jìn)制運(yùn)算的巧用
復(fù)習(xí)
1、&運(yùn)算
有兩個(gè)操作數(shù)a、b,a上的第x位和b上的第x位都是1,那x也是1,否則x為0
a:
0000 0001 0000 1010 0000 0000 0000 0110
a:
0000 0001 0000 1000 0000 0110 0100 0000
a&b
0000 0001 0000 1000 0000 0000 0000 00002、|運(yùn)算
有兩個(gè)操作數(shù)a、b,a上的第x位和b上的第x位只要有一個(gè)是1,那x是1,否則x為0
a:
0000 0001 0000 1010 0000 0000 0000 0110
a:
0000 0001 0000 1000 0000 0110 0100 0000
a|b
0000 0001 0000 1000 0000 0110 0100 01103、^異或
有兩個(gè)操作數(shù)a、b,a上的第x位和b上的第x位不同,那x是1,否則x為0
a:
0000 0001 0000 1010 0000 0000 0000 0110
a:
0000 0001 0000 1000 0000 0110 0100 0000
a^b
0000 0000 0000 0010 0000 0110 0100 01103、~運(yùn)算
有一個(gè)操作數(shù)a,a的第x位上的數(shù)為1,那么結(jié)果的第x位則為0,否則為1
a:
0000 0001 0000 1010 0000 0000 0000 0110
~a:
1111 1110 1111 0101 1111 1111 1111 1001
應(yīng)用場(chǎng)景
情景1:我們?cè)趩?dòng)頁往往會(huì)有一個(gè)啟動(dòng)動(dòng)畫,一般都是啟動(dòng)動(dòng)畫結(jié)束后才會(huì)進(jìn)入Activity,而如果這個(gè)時(shí)候恰好在啟動(dòng)頁需要啟動(dòng)一個(gè)網(wǎng)絡(luò)請(qǐng)求,同時(shí)滿足動(dòng)畫結(jié)束以及網(wǎng)路請(qǐng)求完成(可能是成功回調(diào)也可能是失敗回調(diào))才能進(jìn)入HomeActivity,那這個(gè)時(shí)候一般我們會(huì)用兩個(gè)boolean類型的值去判斷不同的地方是否完成,在條件不多的時(shí)候還好,如果條件增加了,那這種利用boolean值去判斷就顯得非常凌亂
情景2:當(dāng)你需要一系列流程的執(zhí)行的時(shí)候我們往往會(huì)使用責(zé)任鏈模式去解決這個(gè)問題,如果中途出現(xiàn)問題了我們會(huì)把出問題的步驟返回出去,那對(duì)于不同的環(huán)節(jié)我們都可能對(duì)其進(jìn)行做一個(gè)標(biāo)記,這樣在具有耗時(shí)環(huán)節(jié)的場(chǎng)景下,我們可以通過標(biāo)記符來判斷這個(gè)環(huán)節(jié)是否已經(jīng)走過了,可以避免二次執(zhí)行同一個(gè)耗時(shí)操作,那這個(gè)時(shí)候我們?nèi)绾谓o每個(gè)環(huán)節(jié)設(shè)置一個(gè)標(biāo)記呢
以上情景均適用于用位運(yùn)算給一個(gè)數(shù)做多種標(biāo)記
在簡(jiǎn)物中有一個(gè)應(yīng)用場(chǎng)景是這樣的,注冊(cè)環(huán)節(jié)中要對(duì)手機(jī)、驗(yàn)證碼、密碼進(jìn)行逐個(gè)判斷,中途還可以修改驗(yàn)證碼,需要二次判斷,并且每一步執(zhí)行合法后是通過啟動(dòng)一個(gè)交互動(dòng)畫來提供下一個(gè)參數(shù)的設(shè)置入口,那這里就涉及到判斷每個(gè)參數(shù)的合法性問題了,因?yàn)樵谧詈笞?cè)的步驟,我需要判斷每一步是否均合法,當(dāng)然我們可以通過好幾個(gè)if去判斷每一步流程,每次點(diǎn)擊注冊(cè)都走一遍每個(gè)if判斷,但是這樣顯得非常啰嗦,明明已經(jīng)判斷過的了,為什么每次點(diǎn)擊注冊(cè)都要判斷條件呢,是不是可以給判斷過的步驟加上標(biāo)記符,然后每次點(diǎn)擊注冊(cè)只要判斷每個(gè)標(biāo)記符是否在當(dāng)前步驟變量上不就好了?
第一步,給每個(gè)參數(shù)步驟設(shè)置一個(gè)操作數(shù)
/**
* 設(shè)置手機(jī)號(hào)碼
*/
public static final int SET_MOBILE = 0x00010;
/**
* 設(shè)置驗(yàn)證碼
*/
public static final int SET_SMS_CODE = 0x00020;
/**
* 設(shè)置密碼
*/
public static final int SET_PASSWORD = 0x00040;
/**
* 注冊(cè)
*/
public static final int REGISTER = 0x00080;
建一個(gè)當(dāng)前步驟的變量值,用于和參數(shù)步驟進(jìn)行位運(yùn)算
int mRegisterState;
首次初始化,將步驟移到設(shè)置手機(jī)號(hào)碼
mRegisterState |= RegisterState.SET_MOBILE;
那么這個(gè)時(shí)候你可以開始輸入手機(jī)號(hào)碼,輸完了之后點(diǎn)擊下一步,會(huì)調(diào)用網(wǎng)絡(luò)請(qǐng)求判斷手機(jī)號(hào)是否合法,如果不合法,在當(dāng)前界面反饋給用戶,如果合法,將當(dāng)前操作步驟移到填寫驗(yàn)證碼
/**
* 用戶可注冊(cè)
* @param message
*/
@Override
public void userUnavailable(String message) {
mRegisterState |= RegisterState.SET_SMS_CODE;
}
然后填寫驗(yàn)證碼,如果驗(yàn)證碼符合條件(如6位數(shù)字),則把操作步驟移到設(shè)置密碼
mRegisterState |= RegisterState.SET_PASSWORD;
設(shè)置的密碼合法,那就可以移動(dòng)到注冊(cè)步驟了
mRegisterState |= RegisterState.REGISTER;
那么是如何判斷當(dāng)前步驟可以執(zhí)行呢,大概類似以下方法
if((mRegisterState & RegisterState.REGISTER) == RegisterState.REGISTER){
//注冊(cè)
}
剛剛說了,如果我在添加參數(shù)過程中修改了前面的操作,比如驗(yàn)證碼改成了5位(驗(yàn)證碼不合法了),那我如何撤銷步驟呢,很簡(jiǎn)單
public void onTextChanged(int id){
switch (id){
case R.id.sms_code:
/**
* 驗(yàn)證碼不合法
*/
if(isEmpty(getText(mSmsCode)) || isSmsCodeIllegal()){
/**
* 取消設(shè)置密碼步驟
*/
mRegisterState &= ~RegisterState.SET_PASSWORD;
}
....
break;
}
}
對(duì)就是通過以下代碼來撤銷標(biāo)記
mRegisterState &= ~RegisterState.SET_PASSWORD;
可能這么寫不是很明了,我寫一個(gè)java小函數(shù)來給大家演示一下,有興趣的同學(xué)可以拷貝運(yùn)行一下
public class Register {
/**
* 設(shè)置手機(jī)號(hào)碼
*/
public static final int SET_MOBILE = 0x00010;
/**
* 設(shè)置驗(yàn)證碼
*/
public static final int SET_SMS_CODE = 0x00020;
/**
* 設(shè)置密碼
*/
public static final int SET_PASSWORD = 0x00040;
/**
* 注冊(cè)
*/
public static final int REGISTER = 0x00080;
public static void main(String[] args) {
int state = 0;
/**
* 設(shè)置手機(jī)號(hào)
*/
state |= SET_MOBILE;
/**
* 手機(jī)號(hào)合法了,可以設(shè)置驗(yàn)證碼了
*/
state |= SET_SMS_CODE;
/**
* 驗(yàn)證碼合法,可以設(shè)置密碼
*/
state |= SET_PASSWORD;
/**
* 密碼合法,可以注冊(cè)了
*/
state |= REGISTER;
if((state & SET_MOBILE) == SET_MOBILE){
System.out.println("手機(jī)號(hào)設(shè)置合法!");
}else {
System.out.println("請(qǐng)?jiān)O(shè)置手機(jī)號(hào)");
return;
}
if((state & SET_SMS_CODE) == SET_SMS_CODE){
System.out.println("驗(yàn)證碼設(shè)置合法!");
}else {
System.out.println("驗(yàn)證碼不合法");
return;
}
if((state & SET_PASSWORD) == SET_PASSWORD){
System.out.println("密碼設(shè)置合法!");
}else {
System.out.println("密碼不合法");
return;
}
if((state & REGISTER) == REGISTER){
System.out.println("注冊(cè)成功");
}else {
System.out.println("參數(shù)不合法");
return;
}
}
}
輸出結(jié)果是
手機(jī)號(hào)設(shè)置合法!
驗(yàn)證碼設(shè)置合法!
密碼設(shè)置合法!
注冊(cè)成功
那假如注冊(cè)途中修改了驗(yàn)證碼,導(dǎo)致驗(yàn)證碼不合法,執(zhí)行結(jié)果會(huì)怎樣呢?注意看一下注釋
public static void main(String[] args) {
int state = 0;
/**
* 設(shè)置手機(jī)號(hào)
*/
state |= SET_MOBILE;
/**
* 手機(jī)號(hào)合法了,可以設(shè)置驗(yàn)證碼了
*/
state |= SET_SMS_CODE;
/**
* 驗(yàn)證碼合法,可以設(shè)置密碼
*/
state |= SET_PASSWORD;
/**
* 密碼合法,可以注冊(cè)了
*/
state |= REGISTER;
/**
* 用戶又修改了輸入的驗(yàn)證碼,導(dǎo)致驗(yàn)證碼不合法
*/
state &= ~SET_SMS_CODE;
if((state & SET_MOBILE) == SET_MOBILE){
System.out.println("手機(jī)號(hào)設(shè)置合法!");
}else {
System.out.println("請(qǐng)?jiān)O(shè)置手機(jī)號(hào)");
return;
}
if((state & SET_SMS_CODE) == SET_SMS_CODE){
System.out.println("驗(yàn)證碼設(shè)置合法!");
}else {
System.out.println("驗(yàn)證碼不合法");
return;
}
if((state & SET_PASSWORD) == SET_PASSWORD){
System.out.println("密碼設(shè)置合法!");
}else {
System.out.println("密碼不合法");
return;
}
if((state & REGISTER) == REGISTER){
System.out.println("注冊(cè)成功");
}else {
System.out.println("參數(shù)不合法");
return;
}
}
運(yùn)行結(jié)果
手機(jī)號(hào)設(shè)置合法!
驗(yàn)證碼不合法
這樣可能就比較好理解了,當(dāng)然具體這個(gè)環(huán)節(jié)是如何判斷參數(shù)的合法性,并不是這么簡(jiǎn)單,簡(jiǎn)物里面用到責(zé)任鏈模式,可以移步到這篇文章看看Jianwoo中的設(shè)計(jì)模式(7) — 責(zé)任鏈模式
以上就是使用位運(yùn)算來給一個(gè)變量做多種標(biāo)記的小技巧,如果喜歡請(qǐng)不要吝嗇給個(gè)Like!