第 4 章

運算式 (Expression)
本投影片(下稱教用資源)僅授權給採用教用資源相關之旗標書籍為教科書之授課老師(下稱老師)專用,老
師為教學使用之目的,得摘錄、編輯、重製教用資源(但使用量不得超過各該教用資源內容之 80% )以製...
學習目標
 認識運算式
 熟悉各種運算子
 瞭解運算子的優先順序
 資料的轉型
前言
 在上一章中 , 我們已經看過了 Java 程式語言中的各
種資料型別 , 有了這些資料後 , 才能夠進行處理。
 其實在 Java 程式中 , 大部分的處理工作就是運算 ,
像是大家都很熟悉的四則運算、或是邏輯比較 , 以及
低階的...
4-1 甚麼是運算式?
 在 Java 程式語言中 , 大部分的敘述都是由運算式
(Expression) 所構成。所謂的運算式 , 則是由一組
一組的運算子 (Operator ) 與運算元 (Operand) 所
構成。
 其中 , 運...
甚麼是運算式?
 要注意的是 , 不同的運算子所需的運算元數量不同 ,
像是剛剛所提的加法 , 就需要二個運算元 , 這種運算
子稱為二元運算子 (Binary Operator) ;如果運算子
只需單一個運算元 , 就稱為單元運算子 (Un...
甚麼是運算式?
 甚至於運算元也可以是另外一個運算式 , 例如:

 實際在執行時 , Java 會將 5 與 3 * 4 視為是加法的
兩個運算元 , 其中 3 * 4 本身就是一個運算式。
甚麼是運算式?
 每一個運算式都有一個運算結果 , 以加法運算來說 ,
兩個運算元相加的結果就是加法運算式的運算結果。
 當某個運算元為一個運算式時 , 該運算元的值就是這
個運算式的運算結果。以剛剛的例子來說 , 3 * 4 的
結果 1...
甚麼是運算式?
甚麼是運算式?
 其中第 4 與第 5 行的運算式如果將括號去除 , 那麼
兩個運算式完全一樣 , 可是因為加上了括號 , 所以兩
個運算式的順序並不相同 , 最後的結果也不一樣。
 有了以上的基本認識後 , 就可以進一步瞭解各種運算
了。...
運算子的語法
 在以下的章節中 , 我們會在說明每一個運算子之前 ,
列出該運算子的語法 , 舉例來說 , 指定運算子的語法
就是:
 這個意思就表示要使用指定運算子 (=) 的話 , 必須
有 2 個運算元 , 左邊的運算元一定要是一個變...
運算子的語法
 注意到如果某個運算子的
運算元必須受限於某種型別
的話 , 會以右表的單字來
表示:
 否則僅以 opr 來表示該位置需要 1 個運算元。
 另外 , 我們也會以數字字尾區別同類型的不同運算元
, 比如說在乘法運算子中 ,...
4-2 指定運算子 (Assignment Operator)

 指定運算子是用來設定變數的內容 , 它需要 2 個運
算元 , 左邊的運算元必須是一個變數 , 而右邊的運算
元可以是變數、常數或是運算式。
 這個運算子的作用 , 就是將...
指定運算子 (Assignment Operator)
指定運算子 (Assignment Operator)
 其中 , 第 3 行是直接使用字面常數設定變數的值。
 第 4 行則是使用指定運算子將右邊運算式的運算結
果放入左邊的變數 i 中。
 而第 5 行就是使用指定運算子將右邊變數 i...
4-2-1 當成運算元的指定運算式
 前面提過 , 每一個運算式都有一個運算結果 , 而指定
運算式的運算結果就是放入指定運算子左邊變數的內
容。
 因此 , 我們可以運用之前所說:『運算式也可以是某
個運算式的運算元』 , 將指定運算式作...
當成運算元的指定運算式
當成運算元的指定運算式
 在第 4 行中 , 就使用了 j = 3 這個指定運算式當作
加法的其中一個運算元 , 因此 , 這一行的執行過程
就像是這樣:
1. 先將 3 放到變數 j 中 , 所以 j 的內容變成 3, 而 j
= 3 這個...
4-2-2 同時指定給多個變數
 依此類推 , 您也可以將同樣的內容同時設定給 2 個
以上的變數:
同時指定給多個變數
 第 4 行的指定運算會將 3 + 5 這個運算式的運算結
果 (8) 放入變數 l 中 , 而 l = 3 + 5 這個運算式的運
算結果 ( 一樣是 8) 放入 k 中 , 因此 l 與 k 的內
容就都是 8 。
...
4-3 數值 運算
 在所有的運算子中 , 大家最熟悉的可能就要屬數值運
算了 , 撰寫程式時使用率也極高。
 因此 , 在這一小節中 , 所要介紹的是可以運用在數值
型別資料的各種運算子。
4-3-1 四則運算

 在數值運算中 , 最直覺的就是四則運算 , 不過在
Java 中的四則運算中乘法是以 * 表示 , 而除法則是
以 / 表示 , 例如。
四則運算
四則運算
 要特別注意的是 , 由於 i 與 j 都是 int 型別 , 因此
在進行除法時 , 計算的結果也會是整數 , 而不會出現
小數 , 因此當無法整除時 , 所得到的就只是整數的商
。
▪ 瞭解這一點 , 就可以知道在 Java 程...
四則運算
 您可以透過 % 運算子 (Remainder Operator), 來
取得餘數。
四則運算
 如果有任何一個運算元是浮點數 , 那麼除法的結果就
會是浮點數:
4-3-2 遞增 與遞減運算

 由於在設計程式的時候 , 經常會需要將變數的內容遞
增或是遞減 , 因此 Java 也設計了簡單的運算子 , 可
以用來代替使用加法運算子或減法運算子來幫變數加
1 或是減 1 的敘述。
 如果您需要幫變數...
遞增 與遞減運算
遞增 與遞減運算
 在第 4 行使用了遞增運算子 , 因此變數 i 的內容會
變成 5 + 1, 也就是 6 。
 而在第 6 行中 , 使用了遞減運算子 , 因此變數 i 就
又變回 5 了。
 要注意的是 , 遞增或是遞減運算子可以寫...
遞增 與遞減運算
遞增 與遞減運算
 我們分別在第 3 、 8 行將 i 的內容設定為 5, 然後
在第 4 與第 9 行的運算式中使用遞增運算子設定變
數 j 的內容。
 這 2 行程式唯一的差別就是遞增運算子的位置一個
在變數後面、一個在變數前面 , 結...
遞增 與遞減運算
 這種方式稱為後置遞增 運算子 (Post Increment
Operator) 。
 如果把遞增運算子擺在變數之前 , 那麼遞增運算式的
運算結果就會是變數遞增後的內容。
 因此 , 第 9 行的敘述就相當於以下這行...
遞增 與遞減運算
 由於遞增運算式的運算結果是變數遞增後的值 , 所以
++i 會讓 i 的值先變成 6 之後才和 5 相加 , 設定
給 j, 因此 j 就變成 11 了。
 這種方式稱之為前置遞增 運算子 (Prefix Increme...
遞增 與遞減運算
 要特別提醒的是 , 遞增與遞減運算子只能用在變數上
, 也就是說 , 您不能撰寫這樣的程式:

 另外 , 遞增或是遞減運算也可以使用在浮點數值 型別
的變數上 , 而非只能用在整數變數上。
4-3-3 單運算元的正、負號運算子

 + 與 - 除了可以作為加法與減法的運算子外 , 也可
以當成只需要單一運算元的正、負號運算子 , 例如。
單運算元的正、負號運算子

 在第 4 行就利用了負號運算子將 1 + 3 的運算結果
變成負數。
4-4 布林運算 (Logical Operation)
 在這一小節中要介紹的是布林運算 , 也就是運算式的
運算結果是布林值的運算子 , 這類運算對於下一章流
程的控制以及用來表示某種狀態是否成立時特別有用
。
4-4-1 單運算元的反向運算子
(Complement Operator)

 反向運算子只需要單一個布林型別的運算元 , 其運算
結果就是運算元的反向值。
 也就是說 , 如果運算元的值是 true, 那麼反向運算的
結果就是 fals...
單運算元的反向運算子 (Complement Operator)
4-4-2 比較運算子 (Comparison Operator)

 比較運算子需要兩個數值型別的運算元 , 並依據運算
子的比較方式 , 比較兩個運算元是否滿足指定的關係
。
 下表就是個別運算子所要比較的關係。
比較運算子 (Comparison Operator)

 比較運算子的運算結果是一個布林值 , 代表所要比較
的關係是否成立 , 舉例來說。
比較運算子 (Comparison Operator)

 這裡我們將兩個變數的比較關係一一列出 , 您可以檢
視執行的結果。
比較運算子 (Comparison Operator)
 == 與 != 運算子除了可以用在數值資料上以外 , 也
可以用在布林型別的資料 , 其餘的比較運算子則只能
用在數值資料上。例如:
4-4-3 邏輯運算子 (Logical Operator)

 邏輯運算子就相當於是布林資料的比較運算 , 它們都
需要兩個布林型別的運算元。
邏輯運算子 (Logical Operator)
 各個運算子的意義如下:
▪ & 與 && 運算子是邏輯且 (AND) 的意思 , 當兩個
運算元的值都是 true 的時候 , 運算結果就是 true,
否則就是 false 。

▪ | ...
邏輯運算子 (Logical Operator)
 舉例來說:
邏輯運算子 (Logical Operator)
 第 4 、 5 行由於 b 是 false, 所以運算結果為
false 。第 6 、 7 行因為 a 是 true, 所以結果是
true 。
 第 8 行因為 a 與 b 的值不同 ,...
邏輯運算子 (Logical Operator)
 您可能覺得奇怪 , & 、 | 這一組運算子和 && 、 | |
這一組運算子的作用好像一模一樣 , 為什麼要有兩組
功用相同的運算子呢?
 其實這兩組運算子進行的運算雖然相同 , 但是
...
邏輯運算子 (Logical Operator)
邏輯運算子 (Logical Operator)
 您可以發現 , 雖然第 5 與 10 行的運算結果都一樣
, 但是它們造成的效應卻不同。
 在第 10 行中 , 由於 || 運算子左邊的運算元是 true,
因此不需要看右邊的運算元就可...
邏輯運算子 (Logical Operator)
 像這樣只靠左邊的運算元便可推算運算結果 , 而忽略
右邊運算元的方式 , 稱為短路模式 (Short Circuit ),
表示其取捷徑 , 而不會浪費時間繼續計算右邊運算元
的意思。
 ...
4-5 位元運算 (Bitwise Operation)
 在 Java 中 , 整數型別的資料是以 1 或多個位元組
透過 2 進位系統來表示 , 例如 , 以 byte 型別的資
料來說 , 就是用一個 byte 來表示數值 , 其中最高...
位元運算 (Bitwise Operation)
 而負數是以 2 的補數法 (2's Complement), 也就是
其絕 對值 - 1 的補數 (Complement) 表示 , 亦即其
絕對值減 1 後以 2 進位表示 , 然後將每一...
4-5-1 位元邏輯運算子
(Bitwise Logical Operator)

 如果運算式的 2 個運算元都是整數 , 那麼 ^ 、 | 與
& 進行的並不是前面所介紹的布林值邏輯運算 , 而是
進行位元邏輯運算 , 也就是將 2 個運...
位元邏輯運算子 (Bitwise Logical Operator)
位元邏輯運算子 (Bitwise Logical Operator)
 由於 2 的 2 進位表示法為 00000010, 而 -2 的 2
進位表示法為 11111110, 所以 2 | -2 就是針對對應
位元兩兩進行邏輯或的運算 , 對...
位元邏輯運算子 (Bitwise Logical Operator)
 2 & -2 就是針對對應位元兩兩進行邏輯且的運算 , 只
有對應位元的值都是 1 時結果才為 1, 否則即為 0
:

 結果就是 00000010, 亦即 2 。
位元邏輯運算子 (Bitwise Logical Operator)
 2 ^ -2 就是針對對應位元兩兩進行邏輯互斥的運算 ,
當對應位元的值不同時為 1, 否則為 0 :

 結果就是 11111100, 亦即 -4 。
▪ 請特別留心...
4-5-2 單運算元的位元補數運算子
(Bitwise Complement Operator)

 位元補數運算子只需要一個整數型別的運算元 , 運算
的結果就是取運算元的 2 進位補數 , 也就是將運算
元以 2 進位表示後 , 每一個位...
單運算元的位元補數運算子
(Bitwise Complement Operator)
單運算元的位元補數運算子
(Bitwise Complement Operator)
 由於 2 的 2 進位表示為 00000010, 所以取補數即
為將各個位元值反向 , 得到 11111101, 為 -3 。
 而 -2 的 2 進位...
4-5-3 位元移位運算子 (Shift Operator)

 位元移位運算子需要 2 個整數型別的運算元 , 運算
的結果就是將左邊的運算元以 2 進位表示後 , 依據
指定的方向移動右邊運算元所指定的位數。
單運算元的位元補數運算子
(Bitwise Complement Operator)
 移動之後空出來的位元則依據運算子的不同會補上不
同的值:
▪ 如果是 >> 運算子 , 左邊空出來的所有位元都補上原
來最左邊的位元值。
▪ 如果是 >>...
單運算元的位元補數運算子
(Bitwise Complement Operator)
 舉例來說 , 如果左邊的運算元是 int 型別的 2, 並且
只移動一個位元 , 那麼各種移位的運算如下所示:
▪ 2 >> 1
單運算元的位元補數運算子
(Bitwise Complement Operator)
▪ 2 >>> 1

▪ 2 << 1
單運算元的位元補數運算子
(Bitwise Complement Operator)
 但如果左邊的運算元是 -2, 那麼移動 1 個位元的狀
況就會變成這樣:
▪ -2 >> 1
單運算元的位元補數運算子
(Bitwise Complement Operator)
▪ -2 >>> 1

▪ -2 << 1
移位運算與乘除法
 由於移位運算是以位元為單位 , 如果是向左移 1 位 ,
就等於是原本代表 1 的位數移往左成為代表 2 的位
數、而原本代表 2 的位數則往左移 1 位變成代表 4
的位數 , ..., 依此類推 , 最後就相當於把原數...
單運算元的位元補數運算子
(Bitwise Complement Operator)
 實際的範例如下:
單運算元的位元補數運算子
(Bitwise Complement Operator)

▪ 請熟悉補位的規則 , 否則計算結果會差異極大。
型別自動轉換
 在使用移位運算時 , 請特別注意 , 除非左邊的運算元
是 long 型別 , 否則 Java 會先把左邊運算元的值轉
換成 int 型別 , 然後才進行移位的運算。這對於負數
的 >>> 運算會有很大的影響。
 舉例來說 ...
型別自動轉換

 不過實際上因為 -2 會先被轉換成 int 型別 , 因此移
位運算的結果和 Shift.java 一樣 , 還是
2147483647 。
 有關 Java 在進行運算時 , 對於運算元進行的這類轉
換 , 會在 4-7...
4-6 運算式的運算順序
 到上一節為止 , 雖然已經瞭解了 Java 中大部分運算
子的功用 , 不過如果不小心 , 可能會寫出令您自己意
外的程式。舉例來說 , 以下這個運算式:

 您能夠猜出來變數 i 最後的內容是甚麼嗎?
 為了...
4-6-1 運算子間的優先順序 (Operator
Precedence)
 影響運算式解譯的第一個因素 , 就是運算子之間的優
先順序 , 這個順序決定了運算式中不同種類運算子之
間計算的先後次序。請看以下這個運算式:
 在這個運算式中 ...
運算子間的優先順序 (Operator
Precedence)
 可是中間的乘法和右邊的移位運算哪一個比較優先呢
?如果乘法運算子比移位運算子優先 , 5 就會選取乘
法運算子 , 整個運算式就可以解譯成這樣:
 也就是
運算子間的優先順序 (Operator
Precedence)
 那麼接下來的問題就是加法運算子和移位運算子哪一
個優先 , 以便能夠決定中間的 15 要和加法運算子還
是移位運算子結合。
 以此例來說 , 如果加法運算子優先 , 也就是 ...
運算子間的優先順序 (Operator
Precedence)
 但是如果移位運算子比乘法運算子優先的話 , 就會解
譯成這樣:
 那麼 i 的值就會變成是 1 + 3 * 2, 也就是 1 + 6, 變
成 7 了。
 從這裡就可以看到...
運算子間的優先順序 (Operator
Precedence)
運算子間的優先順序 (Operator
Precedence)
 從執行結果可以看出來 , 第 6 行中間的 2 的確是先
選了加法運算子 , 否則 i 的值應該是 2 。
 同樣的道理 , 第 4 行中 , 5 先選了乘法運算子 , 否
...
4-6-2 運算子的結合性 (Associativity)
 另外一個影響運算式計算結果的因素 , 稱為結合性。
 所謂的結合性 , 是指對於優先順序相同的運算子 , 彼
此之間的計算順序。請先看以下這個運算式:
 由於運算式中都是除法運...
運算子間的優先順序 (Operator
Precedence)
 Java 制訂了一套運算子之間的優先順序 , 來決定運
算式的計算順序。
 以剛剛的範例來說 , 乘法運算子最優先 , 其次是加法
運算子 , 最後才是移位運算子 , 因此 ...
運算子的結合性 (Associativity)
 如果以左邊的除法運算子為優先 , 就會解譯為這樣:
 變數 i 的值就會是 4 / 2, 也就是 2 。但如果是以右
邊的除法運算子為優先 , 就會解譯成這樣:
 變數 i 的值就變成 8...
運算子的結合性 (Associativity)
 以剛剛所舉的除法運算子來說 , Java 就規定了它的
結合性為左邊優先。
 也就是說 , 當多個除法運算子串在一起時 , 會先從左
邊的除法運算子開始運算。
 因此 , 在前面的例子中 ...
運算子的結合性 (Associativity)
運算子的結合性 (Associativity)
 指定運算子的結合律就和除法運算子相反 , 是右邊優
先 , 舉例來說:
運算子的結合性 (Associativity)
 其中第 4 行就是依靠指定運算子右邊優先的結合性 ,
否則如果指定運算子是左邊優先結合的話 , 就變成:

 如此將無法正常執行 , 因為第 2 個指定運算子左邊
需要變數作為運算元 , 但...
4-6-3 以括號強制運算順序
 瞭解了運算子的結合性與優先順序之後 , 就可以綜合
這 2 項特性 , 深入瞭解運算式的解譯方法了。
 底下先列出所有運算子的優先順序與結合性 , 方便您
判斷運算式的計算過程 ( 優先等級數目越小越優
先...
以括號強制運算順序
以括號強制運算順序

▪ 請熟悉此表 , 看到考題時才不會混淆運算的次序。
以括號強制運算順序
 為了方便記憶 , 可先背熟以下的簡表 ( 注意:只有二
元運算子的結合性是左邊優先 ) :
解譯運算式
 有了結合性與優先順序的規則 , 任何複雜的運算式都
可以找出計算的順序 , 舉例來說:

 要得到正確的計算結果 , 先在各個運算子下標示優先
等級:
解譯運算式
 從優先等級最高的運算子開始 , 找出它的運算元 , 然
後用括號將這個運算子所構成的運算式標示起來 , 視
為一個整體 , 以做為其他運算子的運算元。
 如果遇到相鄰的運算元優先等級相同 , 就套用結合性
, 找出計算順序。
...
解譯運算式

 實際程式執行結果如下。
解譯運算式
解譯運算式
 可想而知 , 如果每次看到這樣的運算式 , 都要耗費時
間才能確定其運算的順序 , 不但難以閱讀 , 而且撰寫
的時候也可能出錯。
 因此 , 建議您最好使用括號明確的標示出運算式的意
圖 , 以便讓撰寫程式的您以及可能會閱讀...
辨識運算子
 Java 在解譯一個運算式時 , 還有一個重要的特性 ,
就是會從左往右讀取 , 一一辨識出個別的運算子 , 舉
例來說:
解譯運算式
 其中第 4 行指定運算子右邊的運算元如果對於運算
子的歸屬解譯不同 , 結果就會不同。如果解譯為:
 那麼運算結果就是 6, 而且 i 變為 4 、 j 的值不變。
但如果解譯成這樣:
 那麼運算結果就會是 7, 而且 i ...
解譯運算式
 如果解譯成這樣:

 那麼運算結果就是 6, 而且 i 、 j 的值均不變。
 事實上 , Java 會由左往右 , 以最多字元能識別出的
運算子為準 , 因此真正的結果是第一種解譯方式。
 為了避免混淆 , 一樣建議您在...
4-7 資料的轉型 (Type Conversion)
 到目前為止 , 已經把各種運算子的功用以及運算式的
運算順序都說明清楚 , 不過即便如此 , 您還是有可能
寫出令自己意外的運算式。
 因為 Java 在計算運算式時 , 除了套用之...
4-7-1 數值 運算的自動提升 (Promotion)
 請先看看以下這個程式:
數值 運算的自動提升 (Promotion)
 看起來這個程式似乎沒有甚麼問題 , 我們把 1 個
byte 型別的變數值右移 1 個位元 , 然後再放回變數
中 , 但是如果您編譯這個程式 , 就會看到以下的訊息
:
數值 運算的自動提升 (Promotion)
 Java 編譯器居然說可能會漏失資料?
 其實這並不是您的錯 , 而是您不曉得 Java 在計算運
算式時所進行的額外動作。
 以下就針對不同的運算子 , 詳細說明 Java 內部的處
理方...
單元運算子
 對於單元運算子來說 , 如果其運算元的型別是
char 、 byte 、或是 short, 那麼在運算之前就會先將
運算元的值提升為 int 型別。
雙運算元的運算子
 如果是二元運算子 , 規則如下:
1. 如果有任一個運算元是 double 型別 , 那麼就將另一
個運算元提升為 double 型別。
2. 否則 , 如果有任一個運算元是 float, 那麼就將另一
個運算元提升為 f...
數值 運算的自動提升 (Promotion)
 根據這樣的規則 , 就可以知道剛剛的 Promotion.java
為什麼會有問題了。
 由於 Java 會把 >> 運算子兩邊的運算元都提升為
int 型別 , 因此 i >> 1 的運算結...
智慧的整數數值 設定
 如果是使用字面常數設定型別為 char 、 byte 、或是
short 的變數 , 那麼即使 Java 預設會將整數的字面
常數視為 int 型別 , 但只要該常數的值落於該變數所
屬型別可表示的範圍內 , 就可以放...
智慧的整數數值 設定
 編譯時就會錯誤:

 請務必特別注意。
▪ 請熟悉轉型規則 , 這也是考題常見的陷阱。
4-7-2 強制轉型 (Type Casting)
 那麼到底要如何解決這個問題呢?
 如果以保管箱的例子來說 , 除非可以動手把物品擠壓
成能夠放入保管箱的大小 , 否則怎麼樣都放不進去。
 在 Java 中也是一樣 , 除非您可以自行...
強制轉型 (Type Casting)
強制轉型 (Type Casting)
 這個程式和剛剛的 Promoting.java 幾乎一模一樣 ,
差別只在於將第 4 行中原本的移位運算整個括起來 ,
並且使用 (byte) 這個轉型運算子 (Casting
Operator) 將...
強制轉型的風險
 強制轉型雖然好用 , 但因為是把數值範圍比較大的資
料強制轉換為數值範圍比較小的型別 , 因此有可能在
轉型後造成資料值不正確 , 例如:
強制轉型的風險
 在第 6 行中 , 因為 i 的值為 3, 符合 byte 型別的
範圍 , 轉型後並不會有問題。
 但是第 11 行中 , 因為 i 的值為 199, 已經超過
byte 的範圍 , 由 int 強制轉型為 byte 時...
4-7-3 自動轉型
 除了運算子所帶來的轉型效應以外 , 還有一些規則也
會影響到資料的型別 , 進而影響到運算式的運算結果
, 分別在這一小節中一一探討。
字面常數的型別
 除非特別以字尾字元標示 , 否則 Java 會將整數的字
面常數視為是 int 型別 , 而將帶有小數點的字面常
數視為是 double 型別。
 撰寫程式時 , 常常會忽略這一點 , 導致得到意外的運
算結果 , 甚至於...
指定運算子的轉型
 在使用指定運算子時 , 會依據下列規則將右邊的運算
元自動轉型:
▪ 1. 如果左邊運算元型別比右邊運算元型別的數值範圍
要廣 , 就直接將右邊運算元轉型成左邊運算元的型別
。
▪ 2. 如果左邊的運算元是 byte 、 ...
指定運算子的轉型
 這些規則正是我們能夠撰寫以下這樣程式的原因:
指定運算子的轉型
 像是第 3 行指定運算子的右邊就是 int 型別 , 但左
邊是 byte 型別的變數 , 可是因為右邊的運算式僅由
字面常數構成 , 且計算結果符合 byte 的範圍 , 一樣
可以放進去。
 第 4 行則很簡單 , ...
轉型的種類
 在 Java 中 , 由 byte 到 int 這種由數值範圍較小的
基本型別轉換為範圍較大的基本型別 , 稱之為寬 化轉
型 (Widening Primitive Conversion) 。
 反過來的方向 , 則稱之為窄...
4-8 其他運算子
 在這一章的最後 , 還要再介紹一類運算子 , 來簡化您
撰寫程式時的工作。
4-8-1 複合指定運算子
(Compound Assignment Operator)
 如果您在進行數值或是位元運算時 , 左邊的運算元是
個變數 , 而且會將運算結果放回這個變數 , 那麼可以
採用簡潔的方式來撰寫。舉例來說 , 以下這...
複合指定運算子
(Compound Assignment Operator)
 這種作法看起來好像只有節省了一點點打字的時間 ,
但實際上它還做了其他的事情 , 請先看以下的程式:
複合指定運算子
(Compound Assignment Operator)
 其中第 6 行的程式如果不使用複合指定運算子 , 並
不能單純的改成這樣:
 因為 Java 會將 4.6 當成 double 型別 , 而依據上
一節的說明 ...
複合指定運算子
(Compound Assignment Operator)
 而這正是複合指定運算子會幫您處理的細節 , 它會將
左邊運算元的值取出 , 和右邊運算元運算之後 , 強制
將運算結果轉回左邊運算元的型別 , 然後再放回左邊
的...
4-8-2 條件運算子 (Conditional Operator)

 條件運算子是比較特別的運算子 , 它總共需要 3 個
運算元 , 分別以 ? 與 : 隔開。
 第 1 個運算元必須是一個布林值 , 如果這個布林值
為 true, ...
條件運算子 (Conditional Operator)
條件運算子 (Conditional Operator)
 其中 , 第 4 行使用了條件運算子來設定變數 i 的值
, 3 個運算元分別是 j % 2 == 1 這個比較運算
式、 2 、以及 1 。
 意思就是如果 j % 2 == 1...
條件運算子的邊際效應
 要特別留意的是 , 如果第 2 或是第 3 個運算元為一
個運算式而且並不是被選取的運算元時 , 該運算式並
不會進行運算 , 例如:
條件運算子的邊際效應
 程式第 4 行執行時 , 由於第 3 個運算元 j++ 並非
被選取的運算元 , 所以 j++ 並不會執行 , 因此變數 j
的內容還是 17 。
條件運算子運算結果的型別
 使用條件運算子時 , 有一個陷阱很容易忽略 , 那就
是條件運算子運算結果的型別判定。條件運算子依
據的規則如下:
1. 如果後 2 個運算元的型別相同 , 那麼運算結果的型
別也就一樣。
2. 如果第 2 個運算...
條件運算子運算結果的型別
3. 如果第 2 個運算元是 byte 、 short 、或是 char
型別 , 而第 3 個運算元是個由字面常數構成的運算
式 , 並且運算結果為 int, 而且落於第 2 個運算元型
別的數值範圍內 , 那麼條件...
條件運算子運算結果的型別
條件運算子運算結果的型別
 第 5 行看起來並沒有甚麼不對 , 但是實際上連編譯
都無法通過。
 這是因為依據剛剛的規則 , 這一行中的條件運算子會
因為第 3 個運算元 i 是 int 型別 , 使得運算結果變
成 int 型別 , 當然...
1. Given the following code :

What is the result?
A. (i == j) is false

B. (i == j) is true

C. Compilation fails at line...
2. Given the following code:

What is the result ?
A. Output: 558

B. Output: 5553

C. Compilation fails at line 3

D. Com...
3. Given the following code:

Which, inserted at line 4, will compile correctly? (Choose all
that apply.)
A. float x = 128...
4. Given the following code:

What is the result?
A. s = 1236
D. Compilation fails

B. s = 1237

C. s = 1238
E. Runtime er...
5. Given the following code:

What is the result?
A. 245

B. 321

C. 323

D. 333

E. 345
6. Given the following code:

What is the printed value of j?
A. 14
B. -14
C. 15
D. -15
E. An error at line 3 causes compi...
7. Which two of following declarations are illegal?

A. S1

B. S2

C. S3

D. S4

E. S5

F. S6
SCJP ch04
SCJP ch04
Upcoming SlideShare
Loading in …5
×

SCJP ch04

248 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
248
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

SCJP ch04

  1. 1. 第 4 章 運算式 (Expression) 本投影片(下稱教用資源)僅授權給採用教用資源相關之旗標書籍為教科書之授課老師(下稱老師)專用,老 師為教學使用之目的,得摘錄、編輯、重製教用資源(但使用量不得超過各該教用資源內容之 80% )以製作為 輔助教學之教學投影片,並於授課時搭配旗標書籍公開播放,但不得為網際網路公開傳輸之遠距教學、網路教 學等之使用;除此之外,老師不得再授權予任何第三人使用,並不得將依此授權所製作之教學投影片之相關著 作物移作他用。 著作權所有 © 旗標出版股份有限公司
  2. 2. 學習目標  認識運算式  熟悉各種運算子  瞭解運算子的優先順序  資料的轉型
  3. 3. 前言  在上一章中 , 我們已經看過了 Java 程式語言中的各 種資料型別 , 有了這些資料後 , 才能夠進行處理。  其實在 Java 程式中 , 大部分的處理工作就是運算 , 像是大家都很熟悉的四則運算、或是邏輯比較 , 以及 低階的位元運算等等。有了這些運算的功能 , 才能夠 將輸入的資料轉換成所需的結果。  因此 , 在這一章中 , 就要將重點放在 Java 程式語言 所提供的各項運算功能。
  4. 4. 4-1 甚麼是運算式?  在 Java 程式語言中 , 大部分的敘述都是由運算式 (Expression) 所構成。所謂的運算式 , 則是由一組 一組的運算子 (Operator ) 與運算元 (Operand) 所 構成。  其中 , 運算子代表的是運算的種類 , 而運算元則是要 運算的資料。舉例來說:  就是一個運算式 , 其中 + 就是運算子 , 代表要進行 加法運算 , 而要相加的則是 5 與 3 這兩個資料 , 所 以 5 與 3 就是運算元。
  5. 5. 甚麼是運算式?  要注意的是 , 不同的運算子所需的運算元數量不同 , 像是剛剛所提的加法 , 就需要二個運算元 , 這種運算 子稱為二元運算子 (Binary Operator) ;如果運算子 只需單一個運算元 , 就稱為單元運算子 (Unary Operator) 。  另外 , 運算元除了可以是字面常數以外 , 也可以是變 數 , 例如:
  6. 6. 甚麼是運算式?  甚至於運算元也可以是另外一個運算式 , 例如:  實際在執行時 , Java 會將 5 與 3 * 4 視為是加法的 兩個運算元 , 其中 3 * 4 本身就是一個運算式。
  7. 7. 甚麼是運算式?  每一個運算式都有一個運算結果 , 以加法運算來說 , 兩個運算元相加的結果就是加法運算式的運算結果。  當某個運算元為一個運算式時 , 該運算元的值就是這 個運算式的運算結果。以剛剛的例子來說 , 3 * 4 的 結果 12 就是 3 * 4 這個運算式的運算結果 , 它就 會作為前面加法運算的第二個運算元的值 , 相當於將 原本的運算式改寫為 5 + 12 了。  另外 , 在運算式當中 , 也可以如同數學課程中所學的 一樣 , 任意使用配對的小括號 "( )", 明確表示計算的 方式 , 舉例來說。
  8. 8. 甚麼是運算式?
  9. 9. 甚麼是運算式?  其中第 4 與第 5 行的運算式如果將括號去除 , 那麼 兩個運算式完全一樣 , 可是因為加上了括號 , 所以兩 個運算式的順序並不相同 , 最後的結果也不一樣。  有了以上的基本認識後 , 就可以進一步瞭解各種運算 了。以下就分門別類 , 介紹 Java 程式語言中的運算 子。
  10. 10. 運算子的語法  在以下的章節中 , 我們會在說明每一個運算子之前 , 列出該運算子的語法 , 舉例來說 , 指定運算子的語法 就是:  這個意思就表示要使用指定運算子 (=) 的話 , 必須 有 2 個運算元 , 左邊的運算元一定要是一個變數 ( 以 var 表示 ) , 右邊的運算元則沒有限制。
  11. 11. 運算子的語法  注意到如果某個運算子的 運算元必須受限於某種型別 的話 , 會以右表的單字來 表示:  否則僅以 opr 來表示該位置需要 1 個運算元。  另外 , 我們也會以數字字尾區別同類型的不同運算元 , 比如說在乘法運算子中 , 語法就是:  就表示需要 2 個數值型別的運算元。
  12. 12. 4-2 指定運算子 (Assignment Operator)  指定運算子是用來設定變數的內容 , 它需要 2 個運 算元 , 左邊的運算元必須是一個變數 , 而右邊的運算 元可以是變數、常數或是運算式。  這個運算子的作用 , 就是將右邊運算元的值或運算結 果 , 儲存到左邊的變數中。  請看以下的範例。
  13. 13. 指定運算子 (Assignment Operator)
  14. 14. 指定運算子 (Assignment Operator)  其中 , 第 3 行是直接使用字面常數設定變數的值。  第 4 行則是使用指定運算子將右邊運算式的運算結 果放入左邊的變數 i 中。  而第 5 行就是使用指定運算子將右邊變數 i 的內容 放到左邊的變數 j 中 , 因此 , 最後的結果就使得 i 與 j 這兩個變數的內容一模一樣了。
  15. 15. 4-2-1 當成運算元的指定運算式  前面提過 , 每一個運算式都有一個運算結果 , 而指定 運算式的運算結果就是放入指定運算子左邊變數的內 容。  因此 , 我們可以運用之前所說:『運算式也可以是某 個運算式的運算元』 , 將指定運算式作為運算元使 用 , 舉例來說。
  16. 16. 當成運算元的指定運算式
  17. 17. 當成運算元的指定運算式  在第 4 行中 , 就使用了 j = 3 這個指定運算式當作 加法的其中一個運算元 , 因此 , 這一行的執行過程 就像是這樣: 1. 先將 3 放到變數 j 中 , 所以 j 的內容變成 3, 而 j = 3 這個運算式的運算結果也是 3 。 2. 將 j = 3 這個運算式的結果 ( 也就是 3) 與 5 相加 , 得到 8 。 3. 將 (j = 3) + 5 這個運算式的結果 ( 也就是 8) 放入變 數 i 中 , 所以 i 的內容就變成 8 了。
  18. 18. 4-2-2 同時指定給多個變數  依此類推 , 您也可以將同樣的內容同時設定給 2 個 以上的變數:
  19. 19. 同時指定給多個變數  第 4 行的指定運算會將 3 + 5 這個運算式的運算結 果 (8) 放入變數 l 中 , 而 l = 3 + 5 這個運算式的運 算結果 ( 一樣是 8) 放入 k 中 , 因此 l 與 k 的內 容就都是 8 。  依此類推 , 最後 i 、 j 、 k 、 l 這 4 個變數的內容 就全部都是 8 了。
  20. 20. 4-3 數值 運算  在所有的運算子中 , 大家最熟悉的可能就要屬數值運 算了 , 撰寫程式時使用率也極高。  因此 , 在這一小節中 , 所要介紹的是可以運用在數值 型別資料的各種運算子。
  21. 21. 4-3-1 四則運算  在數值運算中 , 最直覺的就是四則運算 , 不過在 Java 中的四則運算中乘法是以 * 表示 , 而除法則是 以 / 表示 , 例如。
  22. 22. 四則運算
  23. 23. 四則運算  要特別注意的是 , 由於 i 與 j 都是 int 型別 , 因此 在進行除法時 , 計算的結果也會是整數 , 而不會出現 小數 , 因此當無法整除時 , 所得到的就只是整數的商 。 ▪ 瞭解這一點 , 就可以知道在 Java 程式中 , (5 / 3) * 2 與 (5 * 2) / 3 的結果是不同的。
  24. 24. 四則運算  您可以透過 % 運算子 (Remainder Operator), 來 取得餘數。
  25. 25. 四則運算  如果有任何一個運算元是浮點數 , 那麼除法的結果就 會是浮點數:
  26. 26. 4-3-2 遞增 與遞減運算  由於在設計程式的時候 , 經常會需要將變數的內容遞 增或是遞減 , 因此 Java 也設計了簡單的運算子 , 可 以用來代替使用加法運算子或減法運算子來幫變數加 1 或是減 1 的敘述。  如果您需要幫變數加 1, 可以使用 ++ 這個遞增 運算 子 (Increment Operator) ;如果需要幫變數減 1, 則可以使用 -- 這個遞減運算子 (Decrement Operator) 。
  27. 27. 遞增 與遞減運算
  28. 28. 遞增 與遞減運算  在第 4 行使用了遞增運算子 , 因此變數 i 的內容會 變成 5 + 1, 也就是 6 。  而在第 6 行中 , 使用了遞減運算子 , 因此變數 i 就 又變回 5 了。  要注意的是 , 遞增或是遞減運算子可以寫在變數的後 面 , 也可以寫在變數的前面 , 但其所代表的意義並不 相同 , 請看這個範例。
  29. 29. 遞增 與遞減運算
  30. 30. 遞增 與遞減運算  我們分別在第 3 、 8 行將 i 的內容設定為 5, 然後 在第 4 與第 9 行的運算式中使用遞增運算子設定變 數 j 的內容。  這 2 行程式唯一的差別就是遞增運算子的位置一個 在變數後面、一個在變數前面 , 結果卻不相同。  主要的原因就是當遞增運算子放在變數後面時 , 雖然 會遞增變數的值 , 但遞增運算式的運算結果卻是變數 尚未遞增 前的原始值。  因此 , 第 4 行的運算式就相當於以下這行程式:
  31. 31. 遞增 與遞減運算  這種方式稱為後置遞增 運算子 (Post Increment Operator) 。  如果把遞增運算子擺在變數之前 , 那麼遞增運算式的 運算結果就會是變數遞增後的內容。  因此 , 第 9 行的敘述就相當於以下這行程式:
  32. 32. 遞增 與遞減運算  由於遞增運算式的運算結果是變數遞增後的值 , 所以 ++i 會讓 i 的值先變成 6 之後才和 5 相加 , 設定 給 j, 因此 j 就變成 11 了。  這種方式稱之為前置遞增 運算子 (Prefix Increment Operator) 。 ▪ 前置與後置的差異往往是考題的陷阱 , 請特別留意。
  33. 33. 遞增 與遞減運算  要特別提醒的是 , 遞增與遞減運算子只能用在變數上 , 也就是說 , 您不能撰寫這樣的程式:  另外 , 遞增或是遞減運算也可以使用在浮點數值 型別 的變數上 , 而非只能用在整數變數上。
  34. 34. 4-3-3 單運算元的正、負號運算子  + 與 - 除了可以作為加法與減法的運算子外 , 也可 以當成只需要單一運算元的正、負號運算子 , 例如。
  35. 35. 單運算元的正、負號運算子  在第 4 行就利用了負號運算子將 1 + 3 的運算結果 變成負數。
  36. 36. 4-4 布林運算 (Logical Operation)  在這一小節中要介紹的是布林運算 , 也就是運算式的 運算結果是布林值的運算子 , 這類運算對於下一章流 程的控制以及用來表示某種狀態是否成立時特別有用 。
  37. 37. 4-4-1 單運算元的反向運算子 (Complement Operator)  反向運算子只需要單一個布林型別的運算元 , 其運算 結果就是運算元的反向值。  也就是說 , 如果運算元的值是 true, 那麼反向運算的 結果就是 false ;反之 , 如果運算元的值是 false, 那麼反向運算的結果就是 true 。  這通常會用來檢查某種狀況是否不成立 , 例如。
  38. 38. 單運算元的反向運算子 (Complement Operator)
  39. 39. 4-4-2 比較運算子 (Comparison Operator)  比較運算子需要兩個數值型別的運算元 , 並依據運算 子的比較方式 , 比較兩個運算元是否滿足指定的關係 。  下表就是個別運算子所要比較的關係。
  40. 40. 比較運算子 (Comparison Operator)  比較運算子的運算結果是一個布林值 , 代表所要比較 的關係是否成立 , 舉例來說。
  41. 41. 比較運算子 (Comparison Operator)  這裡我們將兩個變數的比較關係一一列出 , 您可以檢 視執行的結果。
  42. 42. 比較運算子 (Comparison Operator)  == 與 != 運算子除了可以用在數值資料上以外 , 也 可以用在布林型別的資料 , 其餘的比較運算子則只能 用在數值資料上。例如:
  43. 43. 4-4-3 邏輯運算子 (Logical Operator)  邏輯運算子就相當於是布林資料的比較運算 , 它們都 需要兩個布林型別的運算元。
  44. 44. 邏輯運算子 (Logical Operator)  各個運算子的意義如下: ▪ & 與 && 運算子是邏輯且 (AND) 的意思 , 當兩個 運算元的值都是 true 的時候 , 運算結果就是 true, 否則就是 false 。 ▪ | 與 | | 運算子是邏輯或 (OR) 的意思 , 兩個運算元 中只要有一個是 true, 運算結果就是 true, 只有在兩 個運算元的值都是 false 的情況下 , 運算結果才會是 false 。 ▪ ^ 則是邏輯互斥 (XOR, eXclusive OR) 的運算 , 當兩個運算元的值不同時 , 運算結果為 true, 否則為
  45. 45. 邏輯運算子 (Logical Operator)  舉例來說:
  46. 46. 邏輯運算子 (Logical Operator)  第 4 、 5 行由於 b 是 false, 所以運算結果為 false 。第 6 、 7 行因為 a 是 true, 所以結果是 true 。  第 8 行因為 a 與 b 的值不同 , 所以互斥運算的結 果是 true 。  10 ~ 14 行則因為 a 和 c 都是 true, 所以除了互斥 運算以外 , 其餘的運算結果都是 true 。
  47. 47. 邏輯運算子 (Logical Operator)  您可能覺得奇怪 , & 、 | 這一組運算子和 && 、 | | 這一組運算子的作用好像一模一樣 , 為什麼要有兩組 功用相同的運算子呢?  其實這兩組運算子進行的運算雖然相同 , 但是 && 、 | | 這一組運算子會在左邊的運算元就可以決 定運算結果的情況下忽略右邊運算元。  請看以下這個範例。
  48. 48. 邏輯運算子 (Logical Operator)
  49. 49. 邏輯運算子 (Logical Operator)  您可以發現 , 雖然第 5 與 10 行的運算結果都一樣 , 但是它們造成的效應卻不同。  在第 10 行中 , 由於 || 運算子左邊的運算元是 true, 因此不需要看右邊的運算元就可以知道運算結果為 true 。所以 i++ == 4 這個運算式根本就不會執行 , i 的值也就不會遞增 , 最後看到 i 的值原封不動。  但反觀第 5 行 , 由於是使用 | 運算子 , 所以會把兩 個運算元的值都求出 , 因此就會遞增變數 i 的內容 了。  依此類推 , & 運算子與 && 的運算子也是如此。
  50. 50. 邏輯運算子 (Logical Operator)  像這樣只靠左邊的運算元便可推算運算結果 , 而忽略 右邊運算元的方式 , 稱為短路模式 (Short Circuit ), 表示其取捷徑 , 而不會浪費時間繼續計算右邊運算元 的意思。  在使用這一類的運算子時 , 便必須考量到短路模式的 效應 , 以避免有些我們以為會執行的動作其實並沒有 執行的意外。 ▪ 短路或不短路往往也是考題的陷阱 , 請多留意。
  51. 51. 4-5 位元運算 (Bitwise Operation)  在 Java 中 , 整數型別的資料是以 1 或多個位元組 透過 2 進位系統來表示 , 例如 , 以 byte 型別的資 料來說 , 就是用一個 byte 來表示數值 , 其中最高位 元是正負號 , 像是 2 拆解成 8 個位元就是:
  52. 52. 位元運算 (Bitwise Operation)  而負數是以 2 的補數法 (2's Complement), 也就是 其絕 對值 - 1 的補數 (Complement) 表示 , 亦即其 絕對值減 1 後以 2 進位表示 , 然後將每一個位元的 值反向 , 例如:  位元運算就是以位元為基本單位的運算。
  53. 53. 4-5-1 位元邏輯運算子 (Bitwise Logical Operator)  如果運算式的 2 個運算元都是整數 , 那麼 ^ 、 | 與 & 進行的並不是前面所介紹的布林值邏輯運算 , 而是 進行位元邏輯運算 , 也就是將 2 個運算元的對應位 元兩兩進行邏輯運算 , 得到運算式的結果。  請看範例。
  54. 54. 位元邏輯運算子 (Bitwise Logical Operator)
  55. 55. 位元邏輯運算子 (Bitwise Logical Operator)  由於 2 的 2 進位表示法為 00000010, 而 -2 的 2 進位表示法為 11111110, 所以 2 | -2 就是針對對應 位元兩兩進行邏輯或的運算 , 對應位元中有一個值為 1 則結果即為 1, 否則就是 0 :  結果就是 11111110, 即 -2 。
  56. 56. 位元邏輯運算子 (Bitwise Logical Operator)  2 & -2 就是針對對應位元兩兩進行邏輯且的運算 , 只 有對應位元的值都是 1 時結果才為 1, 否則即為 0 :  結果就是 00000010, 亦即 2 。
  57. 57. 位元邏輯運算子 (Bitwise Logical Operator)  2 ^ -2 就是針對對應位元兩兩進行邏輯互斥的運算 , 當對應位元的值不同時為 1, 否則為 0 :  結果就是 11111100, 亦即 -4 。 ▪ 請特別留心負數的 2 進位表示法 , 否則計算結果會差 之千里。
  58. 58. 4-5-2 單運算元的位元補數運算子 (Bitwise Complement Operator)  位元補數運算子只需要一個整數型別的運算元 , 運算 的結果就是取運算元的 2 進位補數 , 也就是將運算 元以 2 進位表示後 , 每一個位元取反向值 , 例如。
  59. 59. 單運算元的位元補數運算子 (Bitwise Complement Operator)
  60. 60. 單運算元的位元補數運算子 (Bitwise Complement Operator)  由於 2 的 2 進位表示為 00000010, 所以取補數即 為將各個位元值反向 , 得到 11111101, 為 -3 。  而 -2 的 2 進位表示為 11111110, 取補數即為將 各個位元值反向 , 得到 00000001, 為 1 。
  61. 61. 4-5-3 位元移位運算子 (Shift Operator)  位元移位運算子需要 2 個整數型別的運算元 , 運算 的結果就是將左邊的運算元以 2 進位表示後 , 依據 指定的方向移動右邊運算元所指定的位數。
  62. 62. 單運算元的位元補數運算子 (Bitwise Complement Operator)  移動之後空出來的位元則依據運算子的不同會補上不 同的值: ▪ 如果是 >> 運算子 , 左邊空出來的所有位元都補上原 來最左邊的位元值。 ▪ 如果是 >> 以外的移位運算子 , 那麼空出來的位元都 補 0。
  63. 63. 單運算元的位元補數運算子 (Bitwise Complement Operator)  舉例來說 , 如果左邊的運算元是 int 型別的 2, 並且 只移動一個位元 , 那麼各種移位的運算如下所示: ▪ 2 >> 1
  64. 64. 單運算元的位元補數運算子 (Bitwise Complement Operator) ▪ 2 >>> 1 ▪ 2 << 1
  65. 65. 單運算元的位元補數運算子 (Bitwise Complement Operator)  但如果左邊的運算元是 -2, 那麼移動 1 個位元的狀 況就會變成這樣: ▪ -2 >> 1
  66. 66. 單運算元的位元補數運算子 (Bitwise Complement Operator) ▪ -2 >>> 1 ▪ -2 << 1
  67. 67. 移位運算與乘除法  由於移位運算是以位元為單位 , 如果是向左移 1 位 , 就等於是原本代表 1 的位數移往左成為代表 2 的位 數、而原本代表 2 的位數則往左移 1 位變成代表 4 的位數 , ..., 依此類推 , 最後就相當於把原數乘以 2 ; 如果移 2 位 , 就變成乘以 4 了。  相同的道理 , 當使用 >> 時 , 右移 1 位的運算就等 於是除以 2 、右移 2 位就變成除以 4 。  對於整數來說 , 使用位移運算因為不牽涉到數值的計 算 , 會比使用乘、除法來的有效率 , 可以善加利用。
  68. 68. 單運算元的位元補數運算子 (Bitwise Complement Operator)  實際的範例如下:
  69. 69. 單運算元的位元補數運算子 (Bitwise Complement Operator) ▪ 請熟悉補位的規則 , 否則計算結果會差異極大。
  70. 70. 型別自動轉換  在使用移位運算時 , 請特別注意 , 除非左邊的運算元 是 long 型別 , 否則 Java 會先把左邊運算元的值轉 換成 int 型別 , 然後才進行移位的運算。這對於負數 的 >>> 運算會有很大的影響。  舉例來說 , 如果 Shift.java 的第 3 行將 i 、 j 宣告 為 byte, 並且以一個位元組來進行移位運算的話 , -2 >>> 1 的結果應該如下所示。
  71. 71. 型別自動轉換  不過實際上因為 -2 會先被轉換成 int 型別 , 因此移 位運算的結果和 Shift.java 一樣 , 還是 2147483647 。  有關 Java 在進行運算時 , 對於運算元進行的這類轉 換 , 會在 4-7 節說明。
  72. 72. 4-6 運算式的運算順序  到上一節為止 , 雖然已經瞭解了 Java 中大部分運算 子的功用 , 不過如果不小心 , 可能會寫出令您自己意 外的程式。舉例來說 , 以下這個運算式:  您能夠猜出來變數 i 最後的內容是甚麼嗎?  為了確認 i 的內容 , 必須先瞭解當一個運算式中有 多個運算子時 , Java 究竟是如何解譯這個運算式?
  73. 73. 4-6-1 運算子間的優先順序 (Operator Precedence)  影響運算式解譯的第一個因素 , 就是運算子之間的優 先順序 , 這個順序決定了運算式中不同種類運算子之 間計算的先後次序。請看以下這個運算式:  在這個運算式中 , 您也許可以依據數學課程中對於四 則運算的基本認識 , 猜測左邊的加法要比中間的乘法 優先順序低 , 所以 3 會與乘法運算子結合。
  74. 74. 運算子間的優先順序 (Operator Precedence)  可是中間的乘法和右邊的移位運算哪一個比較優先呢 ?如果乘法運算子比移位運算子優先 , 5 就會選取乘 法運算子 , 整個運算式就可以解譯成這樣:  也就是
  75. 75. 運算子間的優先順序 (Operator Precedence)  那麼接下來的問題就是加法運算子和移位運算子哪一 個優先 , 以便能夠決定中間的 15 要和加法運算子還 是移位運算子結合。  以此例來說 , 如果加法運算子優先 , 也就是 16 >> 1, 變成 8 ;如果是移位運算子優先 , 就是 1 + 7, 也是 8 。
  76. 76. 運算子間的優先順序 (Operator Precedence)  但是如果移位運算子比乘法運算子優先的話 , 就會解 譯成這樣:  那麼 i 的值就會變成是 1 + 3 * 2, 也就是 1 + 6, 變 成 7 了。  從這裡就可以看到 , 運算子間的優先順序不同 , 會導 致運算式的運算結果不同。
  77. 77. 運算子間的優先順序 (Operator Precedence)
  78. 78. 運算子間的優先順序 (Operator Precedence)  從執行結果可以看出來 , 第 6 行中間的 2 的確是先 選了加法運算子 , 否則 i 的值應該是 2 。  同樣的道理 , 第 4 行中 , 5 先選了乘法運算子 , 否 則 i 的值應該是 7 。
  79. 79. 4-6-2 運算子的結合性 (Associativity)  另外一個影響運算式計算結果的因素 , 稱為結合性。  所謂的結合性 , 是指對於優先順序相同的運算子 , 彼 此之間的計算順序。請先看以下這個運算式:  由於運算式中都是除法運算子 , 優先順序自然相同 , 但是左邊的除法先算還是右邊的除法先算 , 結果顯然 不同。
  80. 80. 運算子間的優先順序 (Operator Precedence)  Java 制訂了一套運算子之間的優先順序 , 來決定運 算式的計算順序。  以剛剛的範例來說 , 乘法運算子最優先 , 其次是加法 運算子 , 最後才是移位運算子 , 因此 , i 的值實際上 會是 8, 就如同第一種解譯的方式一樣。  以下是實際的程式。
  81. 81. 運算子的結合性 (Associativity)  如果以左邊的除法運算子為優先 , 就會解譯為這樣:  變數 i 的值就會是 4 / 2, 也就是 2 。但如果是以右 邊的除法運算子為優先 , 就會解譯成這樣:  變數 i 的值就變成 8 / 1, 成為 8 了。  和運算子間的優先順序一樣 , 顯然 Java 必須要有一 套規則 , 才能在撰寫程式時 , 確認運算結果的正確性 , 而不會有意外的結果。
  82. 82. 運算子的結合性 (Associativity)  以剛剛所舉的除法運算子來說 , Java 就規定了它的 結合性為左邊優先。  也就是說 , 當多個除法運算子串在一起時 , 會先從左 邊的除法運算子開始運算。  因此 , 在前面的例子中 , 會以左邊的除法運算子優先 , 計算出的結果再成為第 2 個除法運算子的運算元 , 也就是採取第 1 種解譯的方法。來看看實際的程式 。
  83. 83. 運算子的結合性 (Associativity)
  84. 84. 運算子的結合性 (Associativity)  指定運算子的結合律就和除法運算子相反 , 是右邊優 先 , 舉例來說:
  85. 85. 運算子的結合性 (Associativity)  其中第 4 行就是依靠指定運算子右邊優先的結合性 , 否則如果指定運算子是左邊優先結合的話 , 就變成:  如此將無法正常執行 , 因為第 2 個指定運算子左邊 需要變數作為運算元 , 但左邊這個運算式 i = j 的運 算結果並不是變數 , 而是數值。
  86. 86. 4-6-3 以括號強制運算順序  瞭解了運算子的結合性與優先順序之後 , 就可以綜合 這 2 項特性 , 深入瞭解運算式的解譯方法了。  底下先列出所有運算子的優先順序與結合性 , 方便您 判斷運算式的計算過程 ( 優先等級數目越小越優 先) 。
  87. 87. 以括號強制運算順序
  88. 88. 以括號強制運算順序 ▪ 請熟悉此表 , 看到考題時才不會混淆運算的次序。
  89. 89. 以括號強制運算順序  為了方便記憶 , 可先背熟以下的簡表 ( 注意:只有二 元運算子的結合性是左邊優先 ) :
  90. 90. 解譯運算式  有了結合性與優先順序的規則 , 任何複雜的運算式都 可以找出計算的順序 , 舉例來說:  要得到正確的計算結果 , 先在各個運算子下標示優先 等級:
  91. 91. 解譯運算式  從優先等級最高的運算子開始 , 找出它的運算元 , 然 後用括號將這個運算子所構成的運算式標示起來 , 視 為一個整體 , 以做為其他運算子的運算元。  如果遇到相鄰的運算元優先等級相同 , 就套用結合性 , 找出計算順序。  依此類推 , 一直標示到優先等級最低的運算子為止。
  92. 92. 解譯運算式  實際程式執行結果如下。
  93. 93. 解譯運算式
  94. 94. 解譯運算式  可想而知 , 如果每次看到這樣的運算式 , 都要耗費時 間才能確定其運算的順序 , 不但難以閱讀 , 而且撰寫 的時候也可能出錯。  因此 , 建議您最好使用括號明確的標示出運算式的意 圖 , 以便讓撰寫程式的您以及可能會閱讀程式的別人 都能夠一目了然 , 清清楚楚計算的順序。  像是剛剛所舉的例子來說 , 至少要改寫成這樣 , 才不 會對於計算的順序有所誤會:
  95. 95. 辨識運算子  Java 在解譯一個運算式時 , 還有一個重要的特性 , 就是會從左往右讀取 , 一一辨識出個別的運算子 , 舉 例來說:
  96. 96. 解譯運算式  其中第 4 行指定運算子右邊的運算元如果對於運算 子的歸屬解譯不同 , 結果就會不同。如果解譯為:  那麼運算結果就是 6, 而且 i 變為 4 、 j 的值不變。 但如果解譯成這樣:  那麼運算結果就會是 7, 而且 i 不變 , 但 j 會變成 4。
  97. 97. 解譯運算式  如果解譯成這樣:  那麼運算結果就是 6, 而且 i 、 j 的值均不變。  事實上 , Java 會由左往右 , 以最多字元能識別出的 運算子為準 , 因此真正的結果是第一種解譯方式。  為了避免混淆 , 一樣建議您在撰寫這樣的運算式時 , 加上適當的括號來明確分隔運算子。
  98. 98. 4-7 資料的轉型 (Type Conversion)  到目前為止 , 已經把各種運算子的功用以及運算式的 運算順序都說明清楚 , 不過即便如此 , 您還是有可能 寫出令自己意外的運算式。  因為 Java 在計算運算式時 , 除了套用之前所提到的 結合性與優先順序以外 , 還使用了幾條處理資料型別 的規則 , 如果不瞭解這些 , 撰寫程式時就會遇到許多 奇怪不解的狀況。
  99. 99. 4-7-1 數值 運算的自動提升 (Promotion)  請先看看以下這個程式:
  100. 100. 數值 運算的自動提升 (Promotion)  看起來這個程式似乎沒有甚麼問題 , 我們把 1 個 byte 型別的變數值右移 1 個位元 , 然後再放回變數 中 , 但是如果您編譯這個程式 , 就會看到以下的訊息 :
  101. 101. 數值 運算的自動提升 (Promotion)  Java 編譯器居然說可能會漏失資料?  其實這並不是您的錯 , 而是您不曉得 Java 在計算運 算式時所進行的額外動作。  以下就針對不同的運算子 , 詳細說明 Java 內部的處 理方式。
  102. 102. 單元運算子  對於單元運算子來說 , 如果其運算元的型別是 char 、 byte 、或是 short, 那麼在運算之前就會先將 運算元的值提升為 int 型別。
  103. 103. 雙運算元的運算子  如果是二元運算子 , 規則如下: 1. 如果有任一個運算元是 double 型別 , 那麼就將另一 個運算元提升為 double 型別。 2. 否則 , 如果有任一個運算元是 float, 那麼就將另一 個運算元提升為 float 型別。 3. 否則 , 就再看是否有任一個運算元是 long 型別 , 如 果有 , 就將另外一個運算元提升為 long 型別。 4. 如果以上規則都不符合 , 就將 2 個運算元都提升為 int 型別。  簡單來說 , 就是將兩個運算元的型別提升到同一種 型別。
  104. 104. 數值 運算的自動提升 (Promotion)  根據這樣的規則 , 就可以知道剛剛的 Promotion.java 為什麼會有問題了。  由於 Java 會把 >> 運算子兩邊的運算元都提升為 int 型別 , 因此 i >> 1 的運算結果也是 int 型別 , 但是 i 卻是 byte 型別 , 如果想把 int 型別的資料 放到 byte 型別的變數中 , Java 就會擔心數值過大 , 無法符合 byte 型別可以容納的數值範圍。  這就好比如果您想把一個看起來體積比保管箱大的物 品放進保管箱中 , 服務人員自然不會准許。
  105. 105. 智慧的整數數值 設定  如果是使用字面常數設定型別為 char 、 byte 、或是 short 的變數 , 那麼即使 Java 預設會將整數的字面 常數視為 int 型別 , 但只要該常數的值落於該變數所 屬型別可表示的範圍內 , 就可以放入該變數中。  也就是說 , 以下這行程式是可以的:  但此項規則並不適用於 long 型別的字面常數 , 像是 以下這行程式:
  106. 106. 智慧的整數數值 設定  編譯時就會錯誤:  請務必特別注意。 ▪ 請熟悉轉型規則 , 這也是考題常見的陷阱。
  107. 107. 4-7-2 強制轉型 (Type Casting)  那麼到底要如何解決這個問題呢?  如果以保管箱的例子來說 , 除非可以動手把物品擠壓 成能夠放入保管箱的大小 , 否則怎麼樣都放不進去。  在 Java 中也是一樣 , 除非您可以自行保證要放進去 的數值符合 byte 的可接受範圍 , 否則就無法讓您將 int 型別的資料放入 byte 型別的變數中。  這個保證的方法就稱為強制轉型 (Cast), 請看以下的 程式。
  108. 108. 強制轉型 (Type Casting)
  109. 109. 強制轉型 (Type Casting)  這個程式和剛剛的 Promoting.java 幾乎一模一樣 , 差別只在於將第 4 行中原本的移位運算整個括起來 , 並且使用 (byte) 這個轉型運算子 (Casting Operator) 將運算結果轉成 byte 型別。  這等於是告訴 Java 說 , 我要求把運算結果變成 byte 型別 , 後果我自行負責。  透過這樣的方式 , 您就可以將運算結果放回 byte 型 別的變數中了。
  110. 110. 強制轉型的風險  強制轉型雖然好用 , 但因為是把數值範圍比較大的資 料強制轉換為數值範圍比較小的型別 , 因此有可能在 轉型後造成資料值不正確 , 例如:
  111. 111. 強制轉型的風險  在第 6 行中 , 因為 i 的值為 3, 符合 byte 型別的 範圍 , 轉型後並不會有問題。  但是第 11 行中 , 因為 i 的值為 199, 已經超過 byte 的範圍 , 由 int 強制轉型為 byte 時只會留下 最低的 8 個位元 , 使得轉型後 b 的值變成 11000111, 反而變成 -57 了。
  112. 112. 4-7-3 自動轉型  除了運算子所帶來的轉型效應以外 , 還有一些規則也 會影響到資料的型別 , 進而影響到運算式的運算結果 , 分別在這一小節中一一探討。
  113. 113. 字面常數的型別  除非特別以字尾字元標示 , 否則 Java 會將整數的字 面常數視為是 int 型別 , 而將帶有小數點的字面常 數視為是 double 型別。  撰寫程式時 , 常常會忽略這一點 , 導致得到意外的運 算結果 , 甚至於無法正確編譯程式。
  114. 114. 指定運算子的轉型  在使用指定運算子時 , 會依據下列規則將右邊的運算 元自動轉型: ▪ 1. 如果左邊運算元型別比右邊運算元型別的數值範圍 要廣 , 就直接將右邊運算元轉型成左邊運算元的型別 。 ▪ 2. 如果左邊的運算元是 byte 、 short 、或是 char 型別的變數 , 而右邊的運算元是僅由 byte 、 short 、 int 、或是 char 型別的字面常數所構成的運算式 , 並 且運算結果落於左邊變數型別的數值範圍內 , 那麼就 會將右邊運算元自動轉型為左邊運算元的型別。
  115. 115. 指定運算子的轉型  這些規則正是我們能夠撰寫以下這樣程式的原因:
  116. 116. 指定運算子的轉型  像是第 3 行指定運算子的右邊就是 int 型別 , 但左 邊是 byte 型別的變數 , 可是因為右邊的運算式僅由 字面常數構成 , 且計算結果符合 byte 的範圍 , 一樣 可以放進去。  第 4 行則很簡單 , 右邊 byte 型別的資料可以直接 放入左邊 int 型別的變數中。如果您把第 3 行改成 這樣:  那麼由於右邊運算式的運算結果超出了 byte 的範圍 , 連編譯的動作都無法通過。
  117. 117. 轉型的種類  在 Java 中 , 由 byte 到 int 這種由數值範圍較小的 基本型別轉換為範圍較大的基本型別 , 稱之為寬 化轉 型 (Widening Primitive Conversion) 。  反過來的方向 , 則稱之為窄化轉型 (Narrowing primitive Conversion) 。
  118. 118. 4-8 其他運算子  在這一章的最後 , 還要再介紹一類運算子 , 來簡化您 撰寫程式時的工作。
  119. 119. 4-8-1 複合指定運算子 (Compound Assignment Operator)  如果您在進行數值或是位元運算時 , 左邊的運算元是 個變數 , 而且會將運算結果放回這個變數 , 那麼可以 採用簡潔的方式來撰寫。舉例來說 , 以下這行程式:  就可以改寫為:
  120. 120. 複合指定運算子 (Compound Assignment Operator)  這種作法看起來好像只有節省了一點點打字的時間 , 但實際上它還做了其他的事情 , 請先看以下的程式:
  121. 121. 複合指定運算子 (Compound Assignment Operator)  其中第 6 行的程式如果不使用複合指定運算子 , 並 不能單純的改成這樣:  因為 Java 會將 4.6 當成 double 型別 , 而依據上 一節的說明 , 為了讓 i 可以和 4.6 相加 , i 的值會先 被轉換成 double 型別。  因此 i + 4.6 的結果也會是 double 型別 , 但 i 卻是 int 型別 , 因此指定運算在編譯時會發生錯誤。正確 的寫法應該是:
  122. 122. 複合指定運算子 (Compound Assignment Operator)  而這正是複合指定運算子會幫您處理的細節 , 它會將 左邊運算元的值取出 , 和右邊運算元運算之後 , 強制 將運算結果轉回左邊運算元的型別 , 然後再放回左邊 的運算元。這樣一來 , 您就不需要自己撰寫轉換型別 的動作了。 ▪ 一般人很容易忽略這個細微的差異 , 導致計算出錯誤 的結果。  除了 += 以外 , *= 、 / = 、 %= 、 = 、 <<= 、 >>= 、 >>>= 、 &= 、 ^= 、以及 | = 也 是可用的複合指定運算子。
  123. 123. 4-8-2 條件運算子 (Conditional Operator)  條件運算子是比較特別的運算子 , 它總共需要 3 個 運算元 , 分別以 ? 與 : 隔開。  第 1 個運算元必須是一個布林值 , 如果這個布林值 為 true, 就選取第 2 個運算元進行運算 , 否則就選 取第 3 個運算元進行運算 , 作為整個條件運算的結 果。  例如。
  124. 124. 條件運算子 (Conditional Operator)
  125. 125. 條件運算子 (Conditional Operator)  其中 , 第 4 行使用了條件運算子來設定變數 i 的值 , 3 個運算元分別是 j % 2 == 1 這個比較運算 式、 2 、以及 1 。  意思就是如果 j % 2 == 1 成立的話 , 就將變數 i 內 容設為 2, 否則就為 1 。  由於這裡 j 是 17, 所以設立的條件會成立 , 於是變 數 i 變成 2 了。
  126. 126. 條件運算子的邊際效應  要特別留意的是 , 如果第 2 或是第 3 個運算元為一 個運算式而且並不是被選取的運算元時 , 該運算式並 不會進行運算 , 例如:
  127. 127. 條件運算子的邊際效應  程式第 4 行執行時 , 由於第 3 個運算元 j++ 並非 被選取的運算元 , 所以 j++ 並不會執行 , 因此變數 j 的內容還是 17 。
  128. 128. 條件運算子運算結果的型別  使用條件運算子時 , 有一個陷阱很容易忽略 , 那就 是條件運算子運算結果的型別判定。條件運算子依 據的規則如下: 1. 如果後 2 個運算元的型別相同 , 那麼運算結果的型 別也就一樣。 2. 如果第 2 個運算元是 byte 型別 , 而第 3 個運算元 是 short 型別 , 運算結果就是 short 型別。
  129. 129. 條件運算子運算結果的型別 3. 如果第 2 個運算元是 byte 、 short 、或是 char 型別 , 而第 3 個運算元是個由字面常數構成的運算 式 , 並且運算結果為 int, 而且落於第 2 個運算元型 別的數值範圍內 , 那麼條件運算子的運算結果就和第 2 個運算元型別相同。 4. 如果以上條件均不符合 , 那麼運算結果的型別就依據 二元運算子的運算元自動提升規則。 ▪ 請熟悉這些規則 , 以免被一些簡單的考題給難倒。
  130. 130. 條件運算子運算結果的型別
  131. 131. 條件運算子運算結果的型別  第 5 行看起來並沒有甚麼不對 , 但是實際上連編譯 都無法通過。  這是因為依據剛剛的規則 , 這一行中的條件運算子會 因為第 3 個運算元 i 是 int 型別 , 使得運算結果變 成 int 型別 , 當然就無法放入 byte 型別的 b 中了 。  此時 , 只要把運算結果強制轉型為 byte 型別 , 就可 以正常執行了。
  132. 132. 1. Given the following code : What is the result? A. (i == j) is false B. (i == j) is true C. Compilation fails at line 4 D. Compilation fails at line 6 E. There is a runtime error
  133. 133. 2. Given the following code: What is the result ? A. Output: 558 B. Output: 5553 C. Compilation fails at line 3 D. Compilation fails at line 4 E. There is a runtime error
  134. 134. 3. Given the following code: Which, inserted at line 4, will compile correctly? (Choose all that apply.) A. float x = 128.5; B. double x = s.length(); C. byte x = (byte) 120 + 1; D. short x = s.length(); E. int x = 255L;
  135. 135. 4. Given the following code: What is the result? A. s = 1236 D. Compilation fails B. s = 1237 C. s = 1238 E. Runtime error
  136. 136. 5. Given the following code: What is the result? A. 245 B. 321 C. 323 D. 333 E. 345
  137. 137. 6. Given the following code: What is the printed value of j? A. 14 B. -14 C. 15 D. -15 E. An error at line 3 causes compilation fails
  138. 138. 7. Which two of following declarations are illegal? A. S1 B. S2 C. S3 D. S4 E. S5 F. S6

×