1. 程式人生 > >《Java程式設計思想》第3章 操作符

《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()

nextFloat()**即可(nextLong()nextDouble())。

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值只能為truefalse,“大於”和“小於”沒有實際意義。

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值(truefalse)。
注意:如果在應該使用String值的地方使用了布林值,布林值會自動轉換成適當的文字形式。

3.8.1 短路

當使用邏輯操作符時,我們會遇到一種“短路”現象。即一旦能夠明確無誤地確定整個表示式的值,就不再計算表示式餘下部分了。事實上,如果所有的邏輯表示式都有一部分不必計算,那將獲得潛在的效能提升。

3.9 直接常量

直接常量後面的字尾字元標誌了它的型別,若為大寫(或小寫)的L,代表long。大寫(或小寫)字母F,代表float。大寫(或小寫)D,代表double
十六進位制適用於所有整數資料型別,以字首0x(或0X),後面跟隨0-9或小寫(或大寫)的a-f來表示。
八進位制由字首0以及後續的0~7的數字來表示。
在使用十六進位制或八進位制記數法時,以二進位制形式顯示結果將非常有用。通過使用IntegerLong類的靜態方法toBinaryString()很容易地實現這一點。請注意,如果將比較小的型別傳遞給Integer.toBinaryStirng()方法,則該型別自動被轉換為int。

3.9.1 指數記數法

e

3.10 按位操作符

與&,或|,非~,異或^
$=,|=,^=
我們將布林型別作為一種單位元對待。我們可以對它執行按位“與”、“或”、“異或”運算,但不能執行按位“非”。

3.11 移位操作符

移位操作符的運算物件也是二進位制的“位”。移位操作符只可用來處理整數型別。左移位操作符(<<)能按照操作符右側指定的位數將操作符左邊的運算元向左移動(在低位補0)。“有符號”右移操作符(>>)則按照操作符右側指定的位數將操作符左邊的運算元向右移動。“有符號”右移操作符使用“符號擴充套件”:若符號為正,則在高位插入0;若符號為負,則在高位插入1。Java中添加了一種“無符號”右移位操作符(>>>),它使用“零擴充套件”:無論正負,都在高位插入0.
如果對charbyte或者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

不需要,因為所有的資料型別在所有機器中大小是相同的。