《Java程式設計思想》第3章 操作符
原始碼地址:https://github.com/yangxian1229/ThinkingInJava
3.1 更簡單的列印語句
import static net.mindview.util.Print.*;
3.2 使用Java操作符
+,-,*,/,=的用法和其他程式語言類似。
幾乎所有的操作符都只能操作“基本型別”。例外的操作符是“=”、“==”和“!=”,這些操作符能操作所有的物件。除此之外,String類支援“+”和“+=”。
3.3 優先順序
3.4 賦值
“=”
常數不能作為左值(比如說不能4=a;)
基本型別儲存了實際的數值,而並非指向一個物件的引用,所以在為其賦值的時候,是直接將一個地方的內容複製到了另一個地方。
對一個物件進行操作時,我們真正操作的是對物件的引用。所以倘若“將一個物件賦值給另一個物件”,實際是將“引用”從一個地方複製到另一個地方。
//: ch3/Assignment.java // Assignment with objects is a bit tricky. package ch3; import static net.mindview.util.Print.*; import java.nio.file.ProviderNotFoundException; 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; print("1: t1.level:"+t1.level+", t2.level:"+t2.level); t1 = t2;//不再被引用的的物件由“垃圾回收器”自動清理 print("2: t1.level:"+t1.level+", t2.level:"+t2.level); t1.level = 27; print("3: t1.level:"+t1.level+", t2.level:"+t2.level); } }/* Output: 1: t1.level:9, t2.level:47 2: t1.level:47, t2.level:47 3: t1.level:27, t2.level:27 *///:~
別名現象,可以用下面方法避免:
t1.level = t2.level;
這樣就是可以保持兩個物件獨立,而不是將t1和t2繫結到相同的物件。
3.5 算術操作符
加號(+)、減號(-),除號(/)、乘號(*)以及取模操作符(%)。整數除法會直接去掉結果的小數位,而不是四捨五入地園整結果。
建立Random物件時提供種子(用於隨機數生成器的初始化值,隨機數生成器對於特定的種子值總是產生相同的隨機序列。如果在建立過程中沒有傳遞任何引數那麼Java就會將當前時間作為隨機數生成器的種子,並由此在程式每一次執行時都產生不同輸出。)
通過Random類的物件,程式可以生成許多不同型別的隨機數字。做法很簡單,只需呼叫方法**nextInt()和
3.5.1 一元加、減操作符
一元減號用於轉變資料的符號。而一元加號只是為了與一元減號相對應,但是它唯一的作用僅僅是將較小型別的運算元提升為int。
3.6 自動增和遞減
對於字首遞增和字首遞減(如++a或–a),會先執行運算,再生成值。而對於字尾遞增和字尾遞減(如a++或a–),會先生成值,再執行運算。
//: ch3/AutoInc.java
// Demonstrates the ++ and -- operators.
package ch3;
import static net.mindview.util.Print.*;
public class AutoInc {
public static void main(String[] args) {
int i = 1;
print("i = "+i);
print("++i = "+ ++i);
print("i++ = "+ i++);
print("i = "+i);
print("--i = "+ --i);
print("i-- = "+i--);
print("i = "+i);
}
}/* Output:
i = 1
++i = 2
i++ = 2
i = 3
--i = 2
i-- = 2
i = 1
*///:~
3.7 關係操作符
關係操作符生成的是一個boolean結果。
<,>,<=,>=,==,!=
等於和不等於適用於所有的基本資料型別,而其他比較符不適用於boolean型別。因為boolean值只能為true和false,“大於”和“小於”沒有實際意義。
3.7.1 測試物件的等價性
==和!=比較的就是物件的引用。
想要比較兩個物件,使用equals()。但這個方法不適用於“基本型別”,基本型別直接使用==和!=
//: ch3/Equivalence
package ch3;
class Value{
int i;
}
public class Equivalence {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1 == n2);
System.out.println(n1 != n2);
System.out.println(n1.equals(n2));
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
}/* Output:
false
true
true
false
*///:~
equals()的預設行為是比較引用。在自己的新類中應該覆蓋equals()方法。
3.8 邏輯操作符
邏輯操作符 與(&&),或(||),非(!)能根據引數的邏輯關係,生成一個boolean值(true或false)。
注意:如果在應該使用String值的地方使用了布林值,布林值會自動轉換成適當的文字形式。
3.8.1 短路
當使用邏輯操作符時,我們會遇到一種“短路”現象。即一旦能夠明確無誤地確定整個表示式的值,就不再計算表示式餘下部分了。事實上,如果所有的邏輯表示式都有一部分不必計算,那將獲得潛在的效能提升。
3.9 直接常量
直接常量後面的字尾字元標誌了它的型別,若為大寫(或小寫)的L,代表long。大寫(或小寫)字母F,代表float。大寫(或小寫)D,代表double。
十六進位制適用於所有整數資料型別,以字首0x(或0X),後面跟隨0-9或小寫(或大寫)的a-f來表示。
八進位制由字首0以及後續的0~7的數字來表示。
在使用十六進位制或八進位制記數法時,以二進位制形式顯示結果將非常有用。通過使用Integer和Long類的靜態方法toBinaryString()很容易地實現這一點。請注意,如果將比較小的型別傳遞給Integer.toBinaryStirng()方法,則該型別自動被轉換為int。
3.9.1 指數記數法
e
3.10 按位操作符
與&,或|,非~,異或^
$=,|=,^=
我們將布林型別作為一種單位元對待。我們可以對它執行按位“與”、“或”、“異或”運算,但不能執行按位“非”。
3.11 移位操作符
移位操作符的運算物件也是二進位制的“位”。移位操作符只可用來處理整數型別。左移位操作符(<<)能按照操作符右側指定的位數將操作符左邊的運算元向左移動(在低位補0)。“有符號”右移操作符(>>)則按照操作符右側指定的位數將操作符左邊的運算元向右移動。“有符號”右移操作符使用“符號擴充套件”:若符號為正,則在高位插入0;若符號為負,則在高位插入1。Java中添加了一種“無符號”右移位操作符(>>>),它使用“零擴充套件”:無論正負,都在高位插入0.
如果對char,byte或者short型別的數值進行移位處理,那麼在移位進行之前,它們會被轉換為int型別,並且得到的結果也是一個int型別的值。
“移位”可與“等號”(<<=或>>=或>>>=)組合使用。
3.12 三元操作符if-else
boolean-exp ? value0 : value1
3.13 字串操作符+和+=
字串操作符有一些很有趣的行為。如果表示式以一個字串起頭,那麼後續所有運算元都必須是字串型(請記住,編譯器會把雙引號內的字元序列自動轉成字串);
package ch3;
import static net.mindview.util.Print.*;
public class StringOprators {
public static void main(String[] args) {
int x=0,y=1,z=2;
String s = "x,y,z ";
print(s+x+y+z);
print(x+" "+s);//Converts to a String
s += "(summed) = ";
print(s + (x+y+z));
print(""+x);//Shorthand for Integer.toString()
}
}/* Output:
x,y,z 012
0 x,y,z
x,y,z (summed) = 3
0
*/
3.14 使用操作符時常犯的錯誤
=,==,的誤用
3.15 型別轉換操作符
int i = 200; long lng = (long) i; long lng2 = (long)200;
既可對數值進行型別轉換,也可對變數進行型別轉換。
在Java中,型別轉換是一種比較安全的操作。然後,如果要執行一種名為窄化轉換(narrowing conversion)的操作(也就是說,將能容納更多資訊的資料型別轉換為無法容納那麼多資訊的型別),就有可能面臨資訊丟失的危險。此時編譯器會強制我們進行型別轉換。而對於擴充套件轉換(widening conversion),則不必顯式地進行型別轉換,因為新型別肯定能容納原來型別的資訊,不會造成任何資訊的丟失。
Java允許我們把任何基本資料型別轉換成別的基本資料型別,但布林型除外,後者根本不允許進行任何型別的轉換處理。
3.15.1 截尾和舎入
package ch3;
import static net.mindview.util.Print.*;
public class CastingRounding {
public static void main(String[] args) {
double above = 0.7,below = 0.4;
float fabove = 0.7f,fbelow = 0.4f;
print("(int)above:"+(int)above);
print("(int)below:"+(int)below);
print("(int)fabove:"+(int)fabove);
print("(int)fbelow:"+(int)fbelow);
print("Math.round(above):"+Math.round(above));
print("Math.round(below):"+Math.round(below));
print("Math.round(fabove):"+Math.round(fabove));
print("Math.round(fbelow):"+Math.round(fbelow));
}
}/* Output:
(int)above:0
(int)below:0
(int)fabove:0
(int)fbelow:0
Math.round(above):1
Math.round(below):0
Math.round(fabove):1
Math.round(fbelow):0
*///:~
3.16 Java沒有sizeof
不需要,因為所有的資料型別在所有機器中大小是相同的。