在Java里,我們利用運算符操縱對象和數據,并用執行控制語句作出選擇。
1.使用Java運算符
所有運算符都能根據自己的運算對象生成一個值。除此以外,一個運算符可改變運算對象的值,這叫作“副作用”(Side Effect)。
幾乎所有運算符都只能操作“基本類型”(Primitives)。唯一的例外是“=”、“==”和“!=”,它們能操作所有對象(也是對象易令人混淆的一個地方)。除此以外,String類支持“+”和“+=”。
1.1 優先級
運算符的優先級決定了存在多個運算符時一個表達式各部分的計算順序。
1.2 賦值
對基本數據類型的賦值是非常直接的。
但在為對象“賦值”的時候,情況卻發生了變化。對一個對象進行操作時,我們真正操作的是它的句柄。所以倘若“從一個對象到另一個對象”賦值,實際就是將句柄從一個地方復制到另一個地方。這意味著假若為對象使用“C=D”,那么C和D最終都會指向最初只有D才指向的那個對象。
將一個對象傳遞到方法內部時,也會產生別名現象。
1.3 算術運算符
加號(+)、減號(-)、除號(/)、乘號(*)以及模數(%,從整數除法中獲得余數)。
一元加、減運算符。
x = a * (-b);
1.4 自動遞增和遞減
1.5 關系運算符
小于(<)、大于(>)、小于或等于(<=)、大于或等于(>=)、等于(==)以及不等于(!=)。
- =和!=比較的正好就是對象句柄。
- 若想對比兩個對象的實際內容是否相同,又該如何操作呢?此時,必須使用所有對象都適用的特殊方法equals()。但這個方法不適用于“基本類型”,那些類型直接使用==和!=即可。
- 假設您創建了自己的類
這是由于equals()的默認行為是比較句柄。所以除非在自己的新類中改變了equals(),否則不可能表現出我們希望的行為。但要注意equals()的這種行為方式同時或許能夠避免一些“災難”性的事件。
大多數Java類庫都實現了equals(),所以它實際比較的是對象的內容,而非它們的句柄。
1.6 邏輯運算符
AND(&&)、OR(||)以及NOT(!),只可將AND,OR或NOT應用于布爾值。
- 操作邏輯運算符時,我們會遇到一種名為“短路”的情況。
1.7 按位運算符
& | ^ ~
1.8 移位運算符(技術細節待驗證)
<< >> >>>無符號右移
1.9 三元if-else運算符
1.10 逗號
在Java里需要用到逗號的唯一場所就是for循環。
1.11 字串運算符+
1.12 運算符常規操作規則
1.13 造型運算符
- 字面值
最開始的時候,若在一個程序里插入“字面值”(Literal),編譯器通常能準確知道要生成什么樣的類型。但在有些時候,對于類型卻是曖昧不清的。若發生這種情況,必須對編譯器加以適當的“指導”。 - 轉型
大家會發現假若對主數據類型執行任何算術或按位運算,只要它們“比int小”(即char,byte或者short),那么在正式執行運算之前,那些值會自動轉換成int。
表達式中最大的數據類型是決定了表達式最終結果大小的那個類型。若將一個float值與一個double值相乘,結果就是double;如將一個int和一個long值相加,則結果為long。
大家可以看到,除boolean以外,任何一種主類型都可通過造型變為其他主類型。同樣地,當造型成一種較小的類型時,必須留意“縮小轉換”的后果。否則會在造型過程中不知不覺地丟失信息。
將一個float或double值造型成整數值后,總是將小數部分“砍掉”,不作任何進位處理。
1.14 Java沒有“sizeof”
Java不需要sizeof()運算符來滿足這方面的需要,因為所有數據類型在所有機器的大小都是相同的。我們不必考慮移植問題——Java本身就是一種“與平臺無關”的語言。
1.15 復習計算順序
“Ulcer Addicts Really Like C A lot”,即“潰瘍患者特別喜歡(維生素)C”。
1.16 運算符總結
Tests all the operators on all the
primitive data types to show which
ones are accepted by the Java compiler.
- 如果對兩個足夠大的int值執行乘法運算,結果值就會溢出。
2.執行控制
2.1 真和假
所有條件語句都利用條件表達式的真或假來決定執行流程。。注意Java不允許我們將一個數字作為布爾值使用,即使它在C和C++里是允許的(真是非零,而假是零)。
2.2 if-else
2.3 循環語句
while,do-while和for控制著循環。
- 逗號運算符
了逗號運算符——注意不是逗號分隔符;后者用于分隔函數的不同自變量。Java里唯一用到逗號運算符的地方就是for循環的控制表達式。
2.4 break和continue——進一步驗證
Java沒有goto。然而,在break和continue這兩個關鍵字的身上,我們仍然能看出一些goto的影子。
之所以把它們納入goto問題中一起討論,是由于它們使用了相同的機制:標簽。
對Java來說,唯一用到標簽的地方是在循環語句之前。進一步說,它實際需要緊靠在循環語句的前方——在標簽和循環之間置入任何語句都是不明智的。而在循環之前設置標簽的唯一理由是:我們希望在其中嵌套另一個循環或者一個開關。這是由于break和continue關鍵字通常只中斷當前循環,但若隨同標簽使用,它們就會中斷到存在標簽的地方。
label1:
外部循環{
內部循環{
//...
break; //1
//...
continue; //2
//...
continue label1; //3
//...
break label1; //4
}
}
在條件1中,break中斷內部循環,并在外部循環結束。在條件2中,continue移回內部循環的起始處。但在條件3中,continue label1卻同時中斷內部循環以及外部循環,并移至label1處。隨后,它實際是繼續循環,但卻從外部循環開始。在條件4中,break label1也會中斷所有循環,并回到label1處,但并不重新進入循環。也就是說,它實際是完全中止了兩個循環。