- Java從入門到精通(第2版)
- 龍馬高新教育策劃 魔樂科技(MLDN)軟件實訓中心編著 張玉宏主編
- 1696字
- 2019-01-02 04:58:55
第6章 最重要的編程部件—運算符、表達式與語句
本章視頻教學錄像:2小時16分鐘
運算符、表達式和語句是編程的主要部件,能夠使系統程序直接對內存進行操作,從而大大提高程序的執行能力。本章介紹Java運算符的用法、表達式與運算符之間的關系,以及表達式里各種變量的數據類型的轉換等。學完本章,讀者能對Java語句的運作過程有一個更深一層的認識。
本章要點(已掌握的在方框中打鉤)
□ 掌握各種運算符的用法
□ 掌握各種表達式的用法
□ 掌握表達式與運算符的關系
□ 掌握表達式中數據類型的轉換技巧
6.1 運算符
本節視頻教學錄像:48分鐘
程序是由許多語句(statement)組成的,而語句組成的基本單位就是表達式與運算符。Java的運算符可分為4類:算術運算符、關系運算符、邏輯運算符和位運算符。
Java中的語句有多種形式,表達式就是其中的一種形式。表達式是由操作數與運算符所組成的。操作數可以是常量、變量,也可以是方法,而運算符就是數學中的運算符號,如“+”、“-”、“*”、“/”、“%”等。例如下面的表達式(X+100),“X”與“100”都是操作數,而“+”就是運算符。

6.1.1 賦值運算符
若為各種不同類型的變量賦值,就需要用到賦值運算符(Assignment Operator)。簡單的賦值運算符由等號(=)實現,只是把等號右邊的值賦予等號左邊的變量。例如:
int num = 22 ;
需要初學者注意的是,在Java中的賦值運算符“=”,并不是數學意義上的“相等”。例如:
num=num+1; //假設num是前面定義好的變量
這句話的含義是,把變量num的值加1,再賦(=)給num。而在數學意義上,通過約減處理(等式左右兩邊同時約去num),可以得到“0 = 1”,這顯然是不對的。
下面通過一個范例來講解賦值運算符的用法。
【范例6-1】 在程序中用“=”賦值(AssignmentOperator6 1.java)。
01 //在程序中賦值采用“=” 02 public class AssignmentOperator6_1 03 { 04 public static void main(String args[]) 05 { 06 int num=22; //聲明整數變量num,并賦值為22 07 System.out.println("第一次賦值后,num="+num); //輸出num的值 08 num=num-3; //將變量num的值減3之后再賦給num變量 09 System.out.println("改變之后的值,num="+num); //輸出后num的值
10 } 11 }
【運行結果】
程序運行結果如下圖所示。

【范例分析】
程序第06行和第10行均是使用賦值運算符“=”對左側的變量進行賦值。被賦值的變量(如num)的最終值永遠以最近的更新為準,如本例num的最終值為19。
當然,在程序中也可以將等號后面的值賦給其他的變量,例如:
int sum=num1+num2; //num1與num2相加之后的值再賦給變量sum存放
num1與num2的值經過運算后仍然保持不變,sum會因為“賦值”的操作而更改內容。
6.1.2 一元運算符
對于很多表達式而言,運算符前后都會有操作數。但有一類操作符比較特別,它只需要一個操作數。這類運算符稱為一元運算符(或單目運算符,Unary Operator)。下表列出了一元運算符的成員。

舉例說明這些符號的含義。
+5; //表示正數5 ~x; //表示取變量x的補碼
y=-x; //表示負x的值賦給變量y !x; //x的NOT運算,若x為true,則!x返回false。若x為false,則!x返回true x= ~x //表示將x的值取反,并賦給自己
對于上表中“++”和“--”運算符在6.1.8小節專門介紹。下面的程序說明了一元運算符的應用。【范例6-2】的程序聲明了byte類型的變量a及boolean類型的變量b,可以看到這兩個變量分別進行了“~”與“!”運算。
【范例6-2】 一元運算符的使用(UnaryOperator6 2.java)。
01 //下面這段程序說明了一元運算符的使用 02 public class UnaryOperator6_2 03 { 04 public static void main(String args[]) 05 { 06 byte a=java.lang.Byte.MAX_VALUE; //聲明并將其類型最大值賦給a 07 boolean b=false; //聲明布爾變量并賦值為false 08 System.out.println("a="+a+",~a="+(~a)); 09 System.out.println("b="+b+",!b="+(!b)); 10 } 11 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
第6行聲明了byte變量a,并賦值為該類型的最大值,即a的值為127。程序第7行聲明了boolean變量b,賦值為false。
第8行輸出a與~a的運算結果。
第9行輸出b與!b的運算結果。b的值為flase,因此進行“!”運算后,b的值就變成了true。
6.1.3 算術運算符
算術運算符(Arithmetic Operator)用于量之間的運算。算術運算符在數學上經常會用到,下表列出了它的成員。

1.加法運算符“+”
將加法運算符“+”的前后兩個操作數相加,如下面的語句。
System.out.println("3+8="+(3+8)); //直接輸出表達式的值
注意,上面語句的字符串("3 + 8 = ")外的第一個加號“+”為字符串連接符,第二個加號才是加法運算符“+”。
2.減法運算符“-”
將減法運算符“-”前面的操作數減去后面的操作數,如下面的語句。
num=num-3; //將num-3運算之后賦值給num存放 a=b-c; //將b-c運算之后賦值給a存放 120-10; //運算120-10的值
3. 乘法運算符“*”
將乘法運算符“*”的前后兩個操作數相乘,如下面的語句。
b=b*5; //將b*5運算之后賦值給b存放 a=a*a; //將a*a運算之后賦值給a存放 19*2; //運算19*2的值
4. 除法運算符“/”
將除法運算符“/”前面的操作數除以后面的操作數,如下面的語句。
a=b/5; //將b/5運算之后的值賦給a存放 c=c/d; //將c/d運算之后的值賦給c存放 15/5; //運算15/5的值
使用除法運算符時,要特別注意數據類型的問題。若被除數和除數都是整型,且被除數不能被除數整除時,這時輸出的結果為整數(即整型數/整型數=整型數)。這是因為整型變量無法保存小數點后面的數據所致,因此在聲明數據類型及輸出時要特別小心。以下面的程序為例,在程序里給兩個整型變量a、b賦值,并將a / b的運算結果輸出。
【范例6-3】 除法運算符的使用(DivisionOperator6 3.java)。
01 //下面這段程序說明了除法運算符的使用方法 02 public class DivisionOperator6_3 03 { 04 public static void main(String[]args) 05 { 06 int a=13; 07 int b=4; 08 System.out.println("a="+a+",b="+b); 09 System.out.println("a/b="+(a/b)); 10 System.out.println("a/b="+((float)a/b)); //進行強制類型轉換 11 } 12 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
第9行與10行,程序分別做出了不同的輸出。在第9行,因為a、b皆為整數類型,輸出結果也會是整數類型,程序運行結果與實際的值不同。
在第10行,為了保證程序運行結果與實際的值相同,使用了強制性的類型轉換,即將整數類型(int)轉換成浮點數類型(float),程序運行的結果和實際的值相同。
⑸ 取余運算符“%”
將取余運算符“%”前面的操作數除以后面的操作數,取其得到的余數。下面的語句是取余運算符的使用范例。
num=num % 3; //將num%3運算之后賦值給num存放 a=b % c; //將b%c運算之后賦值給a存放 100 % 7; //運算100%7的值為2
以下面的程序為例,聲明兩個整型變量a、b,并分別賦值為5和 3,再輸出a%b的運算結果。
【范例6-4】 取余數(也稱取模)操作(ModuloOperation6 4.java)。
01 //在Java中用%進行取模操作 02 public class ModuloOperation6_4 03 {
04 public static void main(String[]args) 05 { 06 int a=5; 07 int b=3; 08 System.out.println(a+"%"+b+"="+(a % b)); 09 System.out.println(b+"%"+a+"="+(b % a)); 10 } 11 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
設a和b為兩個變量,取余運算的規則是。
其中 是a除以b的取整。

根據上述的公式,對于程序第08行,a%b = 5-1*3 = 2,而對于第09行,b%a= 3 - 0 * 5 =3。這里之所以把這個公式專門說明一下,是因為這里需要初學者注意的是,Java中的取余操作數也可以是負數和浮點數,而在C/C++中,取余運算的操作數只能是整數。例如,在Java中,下面的語句的是合法的。
5%-3=2 //5對負3取余等于2 5.2%3.1=2.1 //根據上述公式,余數為5.2-1*3.1=2.1
6.1.4 邏輯運算符
邏輯運算符只對布爾型操作數進行運算并返回一個布爾型數據。也就是說,邏輯運算符的操作數和運行結果只能是真(true)或者假(false)。常見的邏輯運算符有3個,即與(&&)、或(||)、非(!),如下表所示。

下面是使用邏輯運算符的例子。
1>0&&3>0 //結果為true 1>0||3>8 //結果為true !(1>0) //結果為false
在第1個例子中, 只有1>0(true)和3>0(true)兩個都為真,表達式的返回值為true,即表示這兩個條件必須同時成立才行;在第2個例子中,只要1>0(true)和3>8(false)有一個為真,表達式的返回值即為true。第三個例子中,1>0(true),該結果的否定就是false。
在邏輯運算中,“&&”和“||”屬于所謂的短路邏輯運算符 (Short-Circuit Logical Operators)。對于邏輯運算符“&&”,要求左右兩個表達式都為true時才返回true,如果左邊第一個表達式為false時,它立刻就返回false,就好像短路了一樣立刻返回,省去了一些不必要的計算開銷。
類似的,對于邏輯運算符“||”,要求左右兩個表達式有一個為true時就返回true,如果左邊第一個表達式為true時,它立刻就返回true。
下面的這個程序說明了邏輯運算符的運用。
【范例6-5】 短路邏輯運算符的使用(ShortCircuitLogical6 5.java)。
01 public class ShortCircuitLogical6_5 02 { 03 public static void main(String[]args) 04 { 05 int i=5; 06 boolean flag=(i<3)&&(i<4); //&&短路,(i<4)系統不做運算 07 System.out.println(flag); 08 flag=(i>4)||(i>3); //||短路,(i>3)系統不做運算 09 System.out.println(flag); 10 } 11 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
在第06行,由于i =5,所以(i < 3)為false,對于&&邏輯運算符,其操作數之一為false,其返回值必然為false,故在確定其左邊的操作數為false,對于后一個運算操作數:(i < 4)無需計算,也就是“&&”短路。
類似的,對于“||”運算符,在第08行中,由于i =5,所以(i >4)為true,對于||邏輯運算符,其操作數之一為true,整體返回值必然為true,故在確定其左邊的操作數為true,對于后一個運算操作數:(i > 3)無需計算,也就是“||”短路。
有的時候,我們需要邏輯“與”操作和“或”操作的兩個操作數均需要運算,這時我們就需要使用避免短路的邏輯運算符——“&”和“|”,它們分別是可短路的邏輯運算符(&&和||)一半的字符。
下面的程序說明了短路邏輯運算符“&&”和非短路邏輯運算符的區別。
【范例6-6】 短路邏輯運算符(”&”和 “|”)和非短路邏輯運算符(“&&”和 “||”)對比。
01 public class ShortCircuitLogical6_5_2 02 { 03 public static void main(String args[]) 04 { 05 if(1==2&&1/0==0) { //false&&錯誤=false 06 System.out.println("1:條件滿足!"); 07 } 08 /* 09 if(1==2&1/0==0) { //false&錯誤=錯誤 10 System.out.println("2:條件滿足!"); 11 } 12 */ 13 if(1==1||1/0==0){ //true||錯誤=true 14 System.out.println("3:條件滿足!"); 15 } 16 /* 17 if(1==1|1/0==0){ //true|錯誤=錯誤 18 System.out.println("4:條件滿足!"); 19 } 20 */ 21 } 22 }
【運行結果】
程序運行結果如下。
【代碼詳解】

我們知道,0是不能作為除數的。代碼的第05行和第13行卻可以編譯通過。這是因為第06行邏輯運算符“&&”的第一個操作數是(1 == 2),它的值為false,這樣第二個操作數直接被短路了,也就是不被系統“理睬”,故此第二個操作數中的(1/0)也就“僥幸蒙混過關”。
而第09行的代碼編譯無法通過,這是因為非短路邏輯運算符“&”左右兩邊的操作數均需要運算,任何一個操作數含有不符合Java語法規定的地方,均不被編譯器認可。
類似的,13行可以編譯通過,但含有非法操作符(1/0),但是短路操作符“||”的第一個操作數為(1==1)為true,所以第二個操作數直接被編譯器“忽略”,最終if語句內邏輯判斷值為true,所以14行打印輸出“條件滿足”。
但是同樣的事情并沒有發生在第17行語句上,這是因為非短路邏輯或運算符“|”的左右兩個運算數都被強制運算,因此任何一個操作數不符合Java語法都不行,所以需要注釋掉。
6.1.5 位運算符
位操作是指對操作數以二進制位(bit)為單位進行的運算。其運算的結果為整數。位操作的第一步是把操作數轉換為二進制的形式,然后按位進行布爾運算,運算的結果也為二進制數。位操作運算符(bitwise operators )有7個,如下表所示。

我們用圖例來說明上述運算符的含義,如下圖所示。

下面的程序演示了“按位與”和“按位或”的操作。
【范例6-7】 “按位與”和“按位或”操作(BitwiseOperator6 7.java)。
01 public class BitwiseOperator6_7 02 { 03 public static void main(String args[]){ 04 int x=13; 05 int y=7; 06 System.out.println(x&y); //按位與,結果為5 07 System.out.println(x|y); //按位或,結果為15 08 } 09 }
【運行結果】
程序運行結果如下。

【代碼詳解】
第06行,實現與操作,相“與”的兩位,如果全部為1結果才是1,有一個為0結果就是0。
13的二進制: 00000000 00000000 00000000 00001101
7的二進制: 00000000 00000000 00000000 00000111
“與”&的結果: 00000000 00000000 00000000 00000101
所以輸出的結果為5。
第07行,實現或操作,位“或”的兩位,如果全為0才是0,有一個為1結果就是1。
13的二進制: 00000000 00000000 00000000 00001101
7的二進制: 00000000 00000000 00000000 00000111
“或”|的結果: 00000000 00000000 00000000 00001111
所以輸出的結果為15。
6.1.6 三元運算符
三元(Ternary)運算符也稱三目運算符,它的運算符是“?:”,有三個操作數。操作流程如下:首先判斷條件,如果條件滿足,就會賦予一個變量一個指定的內容(冒號:之前的),不滿足會賦予變量另外的一個內容(冒號之后的),其操作語法如下。
數據類型 變量 = 布爾表達式 ? 條件滿足設置內容 : 條件不滿足設置內容;
下面的程序說明了三元運算符的使用。
【范例6-8】 三元運算符的使用(TernaryOperator6 8.java)。
01 public class TernaryOperator6_8 02 { 03 public static void main(String args[]) 04 { 05 int x=10; 06 int y=20; 07 int result=x>y?x:y; 08 System.out.println("1st result="+result); 09 x=50; 10 result=x>y?x:y; 11 System.out.println("2nd result="+result); 12 } 13 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
result = x > y ? x : y表示的含義是:如果x的內容大于y,則將x的內容賦值給result,否則將y的值賦值給result。對于第07行,x = 10 和y = 20,result的值為y的值,即20。而對第10行,x = 50和y = 20,result的值為x的值,即50。
本質上來講,三元運算符是簡寫的if…else語句。以上的這種操作完全可以利用if…else代替(在第7章我們會詳細描述有關if…else的流程控制知識)。
6.1.7 關系運算符與if語句
if語句通常用于某個條件進行真(true)、假(false)識別。if語句的格式如下。
if (判斷條件) 語句 ;
如果括號中的判斷條件成立,就會執行后面的語句;若是判斷條件不成立,則后面的語句就不會被執行。如下面的程序片段。
if (x > 0) System.out.println("I like Java !");
當x的值大于0時,判斷條件成立,就會執行輸出字符串“I like Java!”的操作;相反,當x的值為0或是小于0時,if語句的判斷條件不成立,就不會進行上述輸出操作。下表列出了關系運算符的成員,這些運算符在數學上也是經常使用的。

在Java中,關系運算符的表示方式和在數學中類似,但是由于賦值運算符為“=”,為了避免混淆,當使用關系運算符“等于”時,就必須用2個等號(==)表示;而關系運算符“不等于”的形式有些特別,用“!=”代表,這是因為想要從鍵盤上取得數學上的不等于符號“≠”較為困難,同時“! ”有"非"的意思,所以就用“!=”表示不等于。
當使用關系運算符(Relational Operator)去判斷一個表達式的成立與否時,若是判斷式成立則會產生一個響應值true,若是判斷式不成立,則會產生響應值false。以下面的程序為例,判斷if語句括號中的條件是否成立,若是成立則執行if后面的語句。
【范例6-9】 關系運算符的使用(RelationOperator6 9.java)。
01 //下面這段程序說明了關系運算符的使用方法,關系運算符返回值為布爾值 02 public class RelationOperator6_9 03 { 04 public static void main(String[]args) 05 { 06 if(5>2) 07 System.out.println("返回值:"+(5>2)); 08 09 if(true) 10 System.out.println("Hello Java!"); 11 12 if((3+6)==(3-6)) 13 System.out.println("I like Java!"); 14 } 15 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
在第6行中,由于5>2的條件成立,所以執行第7行的語句:輸出返回值true。
在第9行中,由于if語句的參數為true,判斷亦成立,所以接著執行第10行的語句:輸出字符串“Hello Java!”。
在第12行中,3+6并不等于3-6,if的判斷條件不成立,所以第13行語句不被執行。
6.1.8 遞增與遞減運算符
遞增與遞減運算符在C / C++中就已經存在了,Java中將它們保留了下來,這是因為它們具有相當大的便利性。下表列出了遞增與遞減運算符的成員。

【范例6-10】 “++”運算符的兩種使用方法(IncrementOperator6 10. java)。
01 //下面這段程序說明了“++”的兩種用法 02 public class IncrementOperator6_10 03 { 04 public static void main(String args[]) 05 { 06 int a=3,b=3; 07 System.out.print("a="+a); //輸出a 08 System.out.println(",a++="+(a++)+",a="+a); //輸出a++和a 09 System.out.print("b="+b); //輸出b 10 System.out.println(",++b="+(++b)+",b="+b); //輸出++b和b 11 } 12 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
在第8行中,輸出a++及運算后的a的值,后綴加1的意思是先執行對該數的操作,再執行加1操作,因此先執行a輸出操作,再將其值自加1,最后輸出,所以第一次輸出3,第二次輸出4。
在第10行中,輸出++b運算后b的值,先執行自加操作,再執行輸出操作,所以兩次都輸出4。
同樣,遞減運算符“--”的使用方式和遞增運算符“++”是相同的,遞增運算符“++”用來將變量值加1,而遞減運算符“--”則是用來將變量值減1。此外,遞增與遞減運算符只能將變量加1或減1,若是想要將變量加減非1的數時,還是得用原來的“a = a+2”的方法。
6.1.9 括號運算符
除了前面所講的內容外,括號()也是Java的運算符,如下表所示。

括號運算符()是用來處理表達式的優先級的。下面是一個簡單的加減乘除式子。
3+5+4*6-7 //未加括號的表達式
相信根據讀者現在所學過的數學知識,這道題應該很容易解開。按加減乘除的優先級(*、/的優先級大于+、-)來計算,這個式子的答案為25。但是如果想先計算3+5+4及6-7之后再將兩數相乘,就必須將3+5+4及6-7分別加上括號,而成為下面的式子。
(3+5+4)*(6-7) //加上括號的表達式
經過括號運算符()的運作后,計算結果為-12,所以括號運算符()可以對括號內表達式的處理順序優先。
6.1.10 運算符的優先級
下表列出了各個運算符的優先級的排列,數字越小的表示優先級越高(優先級排名靠前)。

上表的最后一欄是運算符的結合性(associativity)。
什么是結合性?
結合性就是可以讓程序設計者了解到運算符與操作數之間的關系及其相對位置。舉例來說,當使用同一優先級的運算符時,結合性就非常重要了,它決定誰會先被處理。讀者可以看看下面的例子。
a = b + d / 5 * 4 ;
這個表達式中含有不同優先級的運算符,其中 “/”與“*”的優先級高于“+”,而“+”又高于“=”。但是讀者會發現,“/”與“*”的優先級是相同的,到底d該先除以5再乘以4呢?還是5乘以4后d再除以這個結果呢?結合性的定義就解決了這方面的困擾。算術運算符的結合性為“由左至右”,就是在相同優先級的運算符中,先由運算符左邊的操作數開始處理,再處理右邊的操作數。在這個式子中,由于“/”與“*”的優先級相同,因此d會先除以5再乘以4,得到的結果加上b后,將整個值賦給a存放。
6.2 表達式
本節視頻教學錄像:35分鐘
表達式是由常量、變量或是其他操作數與運算符所組合而成的語句。如下面的例子,均是表達式正確的使用方法。
-49 //表達式由一元運算符“-”與常量49組成 sum+2 //表達式由變量sum、算術運算符與常量2組成 a+b-c/(d*3-9) //表達式由變量、常量與運算符所組成
此外,Java還有一些相當簡潔的寫法,是將算術運算符和賦值運算符結合成為新的運算符。下表列出了這些運算符。

下面的幾個表達式,皆是簡潔的寫法。
a++ //相當于a=a+1 a-=5 //相當于a=a-5 b%=c //相當于b=b%c
a/=b-- //相當于計算a=a/b之后,再計算b--
這種獨特的寫法雖然看起來有些怪異,但是它卻可減少程序的行數,提高運行的速度!請看下面這個范例。
【范例6-11】 程序的簡潔寫法(代碼SimpleWriting6 11.java)。
01 //下面是關于簡潔寫法的一段程序 02 public class SimpleWriting6_11 03 { 04 public static void main(String[]args) 05 { 06 int a=5,b=8; 07 08 System.out.println("改變之前的數是:a="+a+",b="+b); 09 a+=b; //等價于a=a+b; 10 System.out.println("改變之后的數是:a="+a+",b="+b); 11 } 12 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
第6行分別把變量a、b賦值為5和8。
第8行在運算之前先輸出變量a、b的值,a為5,b為8。
第9行計算a+=b,這個語句也就相當于a = a +b,將a+b的值存放到a中。計算5+8的結果后賦值給a存放。
在第10行,再輸出運算之后變量a、b的值,所以a的值變成13,而b仍為8。
下表列出了一些簡潔寫法的運算符及其范例說明。

下面舉一個實例來說明這些簡潔的表達式在程序中該如何應用。以SimpleWriting6_11_2為例,輸入兩個數,經過運算之后,來看看這兩個變量所存放的值有什么變化。
【范例6-12】 程序的簡潔寫法2(SimpleWriting6 11 2.java)。
01 //下面的程序說明了簡潔表達式的使用方法,但這種方式現在已不提倡使用了 02 public class SimpleWriting6_11_2 03 { 04 public static void main(String[]args) 05 { 06 int a=10,b=6; 07 08 System.out.println("改變之前的數:a="+a+",b="+b); 09 a-=b++; //先計算a-b的值,將結果設給a之后,再將b值加1 10 System.out.println("改變之后的數:a="+a+",b="+b); 11 } 12 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
第8行輸出運算前變量a、b的值。在程序中a、b的賦值為10和6,因此輸出的結果a為10,b為6。
第9行計算a -= b++,也就是執行下面這兩條語句。
a=a-b; //(a=10-6=4,所以a=4) b++; //(b=b+1=6+1=7,所以b=7)
第10行,將經過運算之后的結果輸出,即可得到a為4、b為7的答案。
優秀程序設計里有個著名的KISS(Keep It Simple and Stupid )原則,即讓代碼保持簡單,這里Stupid不是愚蠢的意思,而是表示一目了然。一目了然的代碼易于理解和維護。由于上述簡潔表達式的使用方法不易理解,所以目前已不提倡使用了。
6.2.1 算術表達式
算術表達式用于數值計算。它是由算術運算符和變量或常量組成,其結果是一個數值。
【范例6-13】 簡單的算術表達式的使用(ArithmeticExpression6 13.java)。
01 public class ArithmeticExpression6_13 02 { 03 public static void main(String[]args) 04 { 05 int a=12345679,b=9; 06 07 System.out.println("a*b="+a*b); 08 } 09 }
【運行結果】
程序運行結果如下圖所示。

6.2.2 關系表達式
關系表達式常用于程序判斷語句中,由關系運算符組成,其運算結果為邏輯型。
【范例6-14】 簡單的關系表達式的使用(RelationExpression6 14.java)。
01 public class RelationExpression6_14 02 { 03 04 public static void main(String[]args) 05 { 06 int a=5,b=4; 07 boolean t1=a>b; 08 boolean t2=a==b; 09 System.out.println("a>b:"+t1); 10 System.out.println("a==b:"+t2); 11 } 12 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
在第07行,先進行a > b的邏輯判斷,由于a=5,b=4,所以返回true,并賦值給布爾變量t1。
在第08行,先進行a == b的邏輯判斷,由于a=5,b=4,二者不相等,所以返回false,并賦值給布爾變量t2。第09和10行分別把對應的布爾值輸出。
6.2.3 邏輯表達式
用邏輯運算符將關系表達式或邏輯量連接起來的有意義的式子稱為邏輯表達式。邏輯表達式的值也是一個邏輯值,即“true”或“false”。
【范例6-15】 簡單的邏輯表達式的使用(LogicExpression6 15.java)。
01 public class LogicExpression6_15 02 {
03 04 public static void main(String args[]) 05 { 06 boolean t=(1+1==2)&&(1+2==3); 07 System.out.println("(1+1==2)&&(1+2==3):"+t); 08 } 09 }
【運行結果】
程序運行的結果如下圖所示。

【代碼詳解】
在第06行,由于加號(+)運算符的優先級高于邏輯等號(==),所以先進行的是加法操作,(1 +1 == 2) && (1 + 2 ==3) →(2 == 2) && (3 ==3),然后再實施邏輯判斷(2 == 2)返回true,與邏輯判斷(3 ==3)返回true ,顯然,true&& true = true。所以最終的輸出結果為true。
6.2.4 賦值表達式
賦值表達式由賦值運算符和操作數組成,賦值運算符用于給變量賦值。
【范例6-16】 簡單的賦值表達式的使用(AssignExpress6 16.java)。
01 public class AssignExpress6_16 02 { 03 public static void main(String args[]) 04 { 05 int x=123; 06 int y=6; 07 int z; 08 z=x*y-700; 09 System.out.println("Assignment Expression:x*y-700="+z); 10 } 11 }
【運行結果】
程序運行的結果如下圖所示。

【代碼詳解】
賦值表達式的功能是先計算右側表達式的值,再賦予左邊的變量。賦值運算符具有右結合性。在08行,初學者不能將賦值表達式z = x * y - 700理解為將x的值,或x *y 賦值給z,然后再減去700。正確的流程是先計算表達式x * y - 700值,再將計算的結果賦值給z。
6.2.5 表達式的類型轉換
在前面5.6節我們曾提到過數據類型的轉換。除了強制類型轉換外,當int類型遇上了float類型,到底誰是“贏家”,運算的結果是什么數據類型呢,在這里,要再一次詳細討論表達式的類型轉換。
Java是一個很有彈性的程序設計語言,當上述情況發生時,只要堅持“以不流失數據為前提”的大原則,即可進行不同的類型轉換,使不同類型的數據、表達式都能繼續存儲。依照大原則,當Java發現程序的表達式中有類型不相符的情況時,就會依據下列規則來處理類型的轉換。
⑴ 占用字節較少的數據類型轉換成占用字節較多的數據類型。
⑵ 字符類型會轉換成int類型。
⑶ int類型會轉換成float類型。
⑷ 表達式中若某個操作數的類型為double,則另一個操作數也會轉換成double類型。
⑸ 布爾類型不能轉換成其他類型。
⑴和⑵體現“大魚(占字節多的)吃小魚(占字節少的)”思想。⑶和⑷體現“精度高者優先”思想,占據相同字節的類型向浮點數(float、double)靠攏。⑸中體現了Java對邏輯類型堅決“另起爐灶”的原則,布爾類型變量的值只能是true或false,它們和整型數據無關。而在C/C++中,邏輯類型和整型變量的之間關系是“剪不斷,理還亂”,即所有的非零整數都可看作為邏輯“真”,只有0才看做為“假”。
下面的范例說明了表達式類型的自動轉換。
【范例6-17】 表達式類型的自動轉換(TypeConvert6 17.java)。
01 //下面的程序說明了表達式類型的自動轉換問題 02 public class TypeConvert6_17 03 { 04 public static void main(String[]args) 05 { 06 char ch='a'; 07 short a=-2; 08 int b=3; 09 float f=5.3f;
10 double d=6.28; 11 12 System.out.print("(ch/a)-(d/f)-(a+b)="); 13 System.out.println((ch/a)-(d/f)-(a+b)); 14 } 15 }
【運行結果】
程序運行的結果如下圖所示。

【代碼詳解】
先別急著看結果,在程序運行之前可先思考一下,這個復雜的表達式(ch / a)- (d / f) - (a + b)最后的輸出類型是什么?它又是如何將不同的數據類型轉換成相同的呢?讀者可以參考下圖的分析過程。

第12行和第13行分別用了System.out.print和System.out.println方法。二者的區別在于,前者輸出內容后不換行,而后者輸出內容后換行。println中最后兩個字符“ln”實際上是英文單詞“line”的簡寫,表明一個新行。
由于我們知道,轉義字符“\n”也有換行的作用,所以,
System.out.print("我要換行!\n");和語句System.out.println("我要換行!");
是等效的,都能達到輸出內容后換行的效果。
6.3 語句
本節視頻教學錄像:14分鐘
在學會使用運算符和表達式后,就可以寫出最基本的Java程序語句了。表達式由運算符和操作數組成,語句(statement)則由表達式組成。例如 a + b是一個表達式, 加上分號后就成為了下面的形式。
a + b ;
這就是一個語句。計算機執行程序就是由若干條語句進行的。每個語句后用分號(;)隔開。多個語句只要用分號隔開,可以處于同一行,如下面的語句是合法的。
char ch = 'a' ; short a = -2 ; int b = 3 ;
但為了讓程序有良好的可讀性,并且方便添加注釋,我們推薦讀者遵循一條語句占據一行的模式,例如:
char ch='a'; //定義字符型變量ch,并賦值為’a’ short a=-2; //定義短整型變量a,并賦值為-2 int b=3; //定義整型變量b,并賦值為3
6.3.1 語句中的空格
在Java程序語句中,空格是必不可少的。一方面,所有的語言指令都需要借助空格來分割標注。例如下面的語句。
int a; //變量類型(int)和變量(a)之間需要空格隔開
另一方面,雖然Java編譯器在編譯的過程中,會把所有非必需的空格過濾掉,但空格可以使程序更具有可讀性,更加美觀。
例如下面的程序使用了空格,程序的作用很容易看懂。
【范例6-18】 語句中的空格使程序易懂(SpaceDemo6 18.java)。
01 public class SpaceDemo6_18 02 { 03 public static void main(String args[]) 04 { 05 int a; 06 a=7; //等號兩邊使用了空格 07 a=a*a; //等號和乘號兩邊使用了空格 08 System.out.println("a*a="+a); 09 } 10 }
【運行結果】
程序運行結果如下圖所示。

【代碼詳解】
在有了一定的編程經驗之后,讀者可以體會到,源程序除了要實現基本的功能,還要體現出“編程之美”。筆者推薦,在所有可分離的操作符中間都加上一個空格,這樣讓代碼更加舒展,例如對于07行,一般的編程風格為
即
a=a+a; //風格1
而筆者推薦的風格,每個操作符(如這個語句的加號“=”和“+”)左右兩邊都手工多敲一個空格,
a=a+a; //風格2
上述兩個語句在功能上(對于編譯器來說)是完全相同的,但后者更具有美感。當然,對于編程風格,“仁者見仁,智者見智”,這里僅僅是一種推薦,而不是一種必須。
但是對于邏輯判斷的等號“==”、“&&”、“||”、簡寫操作符“+=”、“-=”等、左右移符號“<<”、“>>”及“>>>”等,是不可以用空格隔開的。如果這些符號中間添加空格的話,編譯器就會不“認識”它們,從而無法編譯通過。
6.3.2 空語句
前面所講的語句都要進行一定的操作,但是Java中有一種語句什么也不執行,這就是空語句??照Z句是由一個分號(;)組成的語句。
空語句是什么也不執行的語句。在程序中空語句常常用來作空循環體。例如
while((char) System.in.read()!='\n') { //為了突出空語句,特地加了一個大括號 ; }
本語句的功能是,只要從鍵盤輸入的字符(System.in.read()方法)不是回車則重新輸入。一般來說,while的條件判斷體后不用添加分號的,后面緊跟一個循環體,而這里的循環體為空語句。上述語句可以用下面更加簡潔語句來描述:while(getchar()!='\n') ;
關于while循環的知識點我們會在隨后的第七章詳細描述,這里讀者僅需知道這個概念即可。
空語句還可以用于在調試時留空以待以后添加新的功能。如果不是出于這種目的,一般不建議使用空語句,因為空語句不完成任何功能,但同樣會額外占用計算機資源。
提示
一條Java語句后面可以跟多個分號嗎?如 int x ;; 是合法的嗎?(面試題)如果認為每條語句只能跟一個分號表明本語句結束,那么就會回答“不合法”。事實上,由于多個Java語句可以處于同一行,那么int x ;;就可以解讀為“int x;”這條語句和另外一個空語句“;”共處于一行之上。int x語句后面即使跟10個分號也合法。
6.3.3 聲明語句
在前面已經多次用到了聲明語句。其格式一般如下。
<聲明數據類型> <變量1> …<變量n>;
使用聲明語句可以在每一條語句中聲明一個變量,也可以在一條語句中聲明多個變量。還可以在聲明變量的同時,直接與賦值語句連用為變量賦值。例如
int a; //一條語句中聲明一個變量 int x,y; //一條語句中聲明多個變量 int t=1; //聲明變量的同時,直接為變量賦值
如果對聲明的成員變量沒有賦值,那么將賦為默認的值。默認初始值:整型的為0;布爾類型變量默認值為false;引用數據類型和字符串類型默認都為null。更加詳細的聲明讀者可以參閱5.7節。
6.3.4 賦值語句
除了可以在聲明語句中為變量賦初值外,還可以在程序中為變量重新賦值,這就用到了賦值語句。
例如:
pi = 3.1415; r = 25; s = pi*r*r;
在程序代碼中,使用賦值語句給變量賦值,賦值符號右邊可以是一個常量或變量,也可以是一個表達式。程序在運行時先計算表達式的值,然后將結果賦給等號左邊的變量。
6.4 高手點撥
本節視頻教學錄像:9分鐘
1. &和&&、|和||的關系是怎么樣?(Java面試題)
答:對于“與操作”:有一個條件不滿足,結果就是false。普通與(&):所有的判斷條件都要執行;短路與(&&):如果前面有條件已經返回了false,不再向后判斷,那么最終結果就是false。
對于“或操作”:有一個條件滿足,結果就是true。對于普通或(|):所有的判斷條件都要執行;短路或(||):如果前面有條件返回了true,不再向后判斷,那么最終結果就是true。
2. 遞增與遞減運算符
遞增與遞減運算符通常單獨使用,不與其他操作符一起組成語句。
3. 位運算的技巧
任何數與 0000 0001(二進制) 進行或(|)運算后,第一位將變為1,與 1111 1110(二進制)進行與(&)運算后,第一位將變為0。
位運算通常用于設置或獲取標志位,及判斷相應的操作是否成功。
6.5 實戰練習
本節視頻教學錄像:25分鐘
1. 編寫程序,計算表達式“((12345679*9)>(97654321*3))? true : false”的值。
2. 編寫程序,實現生成一隨機字母(a-z,A-Z),并輸出,運行結果如下圖所示。
拓展知識。
⑴ Math.random()返回隨機 double 值,該值大于等于 0.0 且小于 1.0。
例如: double rand = Math.random(); // rand 儲存著[0,1) 之間的一個小數
⑵ 大寫字母A~Z對應整數65 ~ 90、小寫字母a~z對應整數97 ~ 122。

3. 編寫程序,實現產生(或輸入)一隨機字母(a-z,A-Z),轉為大寫形式,并輸出。請分別使用三元運算和位運算實現,運行結果如下圖所示。
拓展知識點。
⑴ 大寫字母A~Z對應整數65 ~ 90、小寫字母a~z對應整數97 ~ 122。
⑵ 可以使用 0x 表示16進制數,如0x10 表示16進制的 10。

