Thinking in Java(2-1) 運算子入門:深入理解與應用

Java 作為一門強大的編程語言,其運算子(Operators)在日常編程中扮演著至關重要的角色。本文將帶領讀者深入了解 Java 中的各種運算子,從基本概念到賦值行為,並通過實例解析,讓您對 Java 運算子有一個全面而系統的認識。
一、運算子基礎
1. 運算子的作用
在 Java 中,運算子接受一個或多個參數(也稱為操作數,Operands),並生成一個新值。有些運算子還會直接改變操作數本身的值,例如:
- 自增運算子(
++
) - 自減運算子(
--
) - 賦值運算子(
=
)
這些運算子在操作過程中,會直接修改操作數的值。
2. 運算子與方法的比較
雖然運算子的參數形式與普通的方法調用不同,但實際上效果相同。例如:
int sum = x + y; // 使用運算子
int sum = add(x, y); // 使用方法
3. 常見運算子
Java 中的 +
、-
、*
、/
、=
等常見運算子與其他編程語言(如 C++、Python)類似。
4. 運算子的適用類型
大多數運算子(如算術運算子)僅適用於基本類型(Primitives),如 int
、float
等。但也有例外:
- 賦值運算子(
=
) - 等於運算子(
==
) - 不等於運算子(
!=
)
這些運算子可以操作所有物件。
5. 特殊的字串運算符
在 Java 中,String
類別特別支持 +
和 +=
運算子,用於連接字串。例如:
String greeting = "Hello, " + "World!";
提示: 當+
運算子用於字串和非字串類型的組合時,Java 編譯器會自動將非字串元素轉換為String
。這使得連接String
和其他數據類型變得非常方便。
二、運算子優先級(Precedence)
1. 基本原則
Java 中,運算子的優先級遵循一般數學中的規則:
- 先乘除,後加減。
- 括號內的運算優先進行。
2. 使用括號控制運算順序
為了精確控制運算順序,可以使用括號。例如:
public class Precedence {
public static void main(String[] args) {
int x = 1, y = 2, z = 3;
int a = x + y - 2/2 + z; // 計算順序:2/2 -> x + y -> 結果 - 1 -> 加上 z
int b = x + (y - 2)/(2 + z); // 括號內優先:y - 2 和 2 + z,然後計算除法,最後加上 x
System.out.println("a = " + a + " b = " + b);
}
}
/* 輸出:
a = 5 b = 1
*/
在以上代碼中:
a
的計算過程:2/2
計算結果為1
。- 然後按照加減法從左到右計算:
1 + 2 - 1 + 3 = 5
。
b
的計算過程:- 括號內先計算:
(2 - 2) = 0
,(2 + 3) = 5
。 - 然後進行除法:
0 / 5 = 0
。 - 最後加上
x
的值:1 + 0 = 1
。
- 括號內先計算:
三、賦值(Assignment)
1. 基本概念
- 賦值運算子(
=
):將等號右邊的值複製給左邊的變量。 - 右值(R-value):可以是常數、變量或表達式。
- 左值(L-value):必須是一個已命名的變量,有實際的存儲空間來保存值。
例如:
int a;
a = 4; // 合法
4 = a; // 不合法,因為 4 不是變量,無法存儲值
2. 物件的賦值行為
當物件進行賦值時,實際上是複製了物件的引用(Reference),而不是物件本身。因此,兩個引用將指向同一個物件,這被稱為別名現象(Aliasing)。
示例解析
class Tank {
int level;
}
public class Assignment {
public static void main(String[] args) {
Tank t1 = new Tank();
Tank t2 = new Tank();
t1.level = 9;
t2.level = 47;
System.out.println("1: t1.level: " + t1.level + ", t2.level: " + t2.level);
t1 = t2;
System.out.println("2: t1.level: " + t1.level + ", t2.level: " + t2.level);
t1.level = 27;
System.out.println("3: t1.level: " + t1.level + ", t2.level: " + t2.level);
}
}
/* 輸出:
1: t1.level: 9, t2.level: 47
2: t1.level: 47, t2.level: 47
3: t1.level: 27, t2.level: 27
*/
解析:
- 初始狀態:
t1.level = 9
t2.level = 47
- 執行
t1 = t2;
後:t1
和t2
指向同一個Tank
物件(原先t1
指向的物件將被垃圾回收)。- 因此,
t1.level
和t2.level
都為47
。
- 修改
t1.level = 27;
後:- 由於
t1
和t2
指向同一個物件,所以兩者的level
都變為27
。
- 由於
避免別名現象的方法:
如果希望複製物件的值,而不是引用,可以在賦值時創建一個新的物件,或實現物件的複製方法。
3. 方法調用中的別名問題
在方法調用時,傳遞的物件參數實際上也是引用,這可能導致在方法內對參數的修改會影響到原始物件。
示例解析
class Letter {
char c;
}
public class PassObject {
static void f(Letter y) {
y.c = 'z';
}
public static void main(String[] args) {
Letter x = new Letter();
x.c = 'a';
System.out.println("1: x.c: " + x.c);
f(x);
System.out.println("2: x.c: " + x.c);
}
}
/* 輸出:
1: x.c: a
2: x.c: z
*/
解析:
- 在主方法中,創建了物件
x
,並將其屬性c
賦值為'a'
。 - 調用方法
f(x);
,傳遞了物件x
的引用。 - 在方法
f
中,修改了參數y
的屬性c
為'z'
。 - 由於
y
和x
引用同一個物件,因此x.c
的值也被改變。
注意: 在 Java 中,方法調用時傳遞的是物件引用的副本,但引用指向的物件是同一個。因此,對參數物件的修改會影響到原始物件。
四、總結
本文深入探討了 Java 中運算子的基本概念、優先級以及賦值行為。通過實例,我們了解了:
- 運算子如何與操作數交互並生成新值。
- 運算子的優先級如何影響表達式的計算順序。
- 賦值運算子在基本類型和物件上的不同行為。
- 別名現象以及在方法調用中物件引用的傳遞方式。
理解這些概念對於編寫高效且無錯的 Java 程式至關重要。希望本文能夠幫助您在學習 Java 的道路上更進一步。
Comments ()