android面試題:Java基礎(chǔ)(變量賦值陷阱)
下面的程序使用了復(fù)合的異或賦值操作符,它所展示的技術(shù)是一種編程習(xí)俗。那么它會打印出什么呢?
public class CleverSwap{
publicstatic void main(String[] args){
intx = 1984; // (0x7c0)
inty = 2001; // (0x7d1)
x^=y^= x^= y;
System.out.println("x=" + x + "; y= " + y);
}
}
就像其名稱所暗示的,這個程序應(yīng)該交換變量x和y的值。如果你運(yùn)行它,就會發(fā)現(xiàn)很悲慘,它失敗了,打印的是
x = 0; y = 1984。
交換兩個變量的最顯而易見的方式是使用一個臨時變量:
int tmp = x;
x = y;
y = tmp;
很久以前,當(dāng)中央處理器只有少數(shù)寄存器時,人們發(fā)現(xiàn)可以通過利用異或操作符(^)的屬性(x ^ y ^ x) == y來避免使用臨時變量:
x = x ^ y;
y = y ^ x;
x = y ^ x;
這個慣用法曾經(jīng)在C編程語言中被使用過,并進(jìn)一步被構(gòu)建到了C++中,但是它并不保證在二者中都可以正確運(yùn)行。但是有一點(diǎn)是肯定的,那就是它在Java中肯定是不能正確運(yùn)行的。
Java語言規(guī)范描述到:操作符的操作數(shù)是從左向右求值的。為了求表達(dá)式x ^= expr的值,x的值是在計算expr之前被提取的,并且這兩個值的異或結(jié)果被賦給變量x。在CleverSwap程序中,變量x的值被提取了兩次——每次在表達(dá)式中出現(xiàn)時都提取一次——但是兩次提取都發(fā)生在所有的賦值操作之前。
下面的代碼段詳細(xì)地描述了將互換慣用法分解開之后的行為,并且解釋了為什么產(chǎn)生的是我們所看到的輸出:
// Java中x^= y^= x^= y的實際行為
int tmp1 = x ; // x在表達(dá)式中第一次出現(xiàn)
int tmp2 = y ; // y的第一次出現(xiàn)
int tmp3 = x ^ y ; // 計算x ^ y
x = tmp3 ; // 最后一個賦值:存儲x ^ y 到x
y = tmp2 ^ tmp3 ; // 第二個賦值:存儲最初的x值到y(tǒng)中
x = tmp1 ^ y ; // 第一個賦值:存儲0到x中
在C和C++中,并沒有指定表達(dá)式的計算順序。當(dāng)編譯表達(dá)式x ^= expr時,許多C和C++編譯器都是在計算expr之后才提取x的值的,這就使得上述的慣用法可以正常運(yùn)轉(zhuǎn)。盡管它可以正常運(yùn)轉(zhuǎn),但是它仍然違背了C/C++有關(guān)不能在兩個連續(xù)的序列點(diǎn)之間重復(fù)修改變量的規(guī)則。因此,這個慣用法的行為在C和C++中也沒有明確定義。
為了看重其價值,我們還是可以寫出不用臨時變量就可以互換兩個變量內(nèi)容的Java表達(dá)式的.。但是它同樣是丑陋而無用的: y= (x^= (y^= x))^ y ;
總之:在單個的表達(dá)式中不要對相同的變量賦值兩次。表達(dá)式如果包含對相同變量的多次賦值,就會引起混亂,并且很少能夠執(zhí)行你希望的操作。即使對多個變量進(jìn)行賦值也很容易出錯。更一般地講,要避免所謂聰明的編程技巧。它們都是易于產(chǎn)生bug的,很難以維護(hù),并且運(yùn)行速度經(jīng)常是比它們所替代掉的簡單直觀的代碼要慢。
【android面試題:Java基礎(chǔ)(變量賦值陷阱)】相關(guān)文章:
android面試題及答案精選11-12
最新android面試題及答案11-07
Java軟件測試面試題06-20
java多線程面試題02-19
Java的面試題和答案10-30
公司JAVA開發(fā)面試題06-03
java前端開發(fā)面試題05-09
Java Web基礎(chǔ)筆試題06-06
關(guān)于Java泛型的面試題04-12
華為的Java面試題及答案11-22