數據的運算
既然是“計算機”,那麼其主要功能就是“計算”了。我們平時使用計算機打遊戲、看電影、聽音樂、上網、處理文檔、科學研究等行爲,本質上都是將各種問題轉換成了計算的問題。
常用的計算包括算術運算、賦值運算、比較運算、邏輯運算、位運算等。表示運算的符號就是運算符。
下面我們來一一學習各種運算和對應的運算符。
算術運算
Java中的算術運算,是以加減乘除爲基礎的一些運算方法。包括:
運算符 | 說明 | 示例 | 結果 |
---|---|---|---|
+ | 正號 | i=10; m=+i; | m爲10 |
- | 負號 | i=10; m=-i; | m爲-10 |
+ | 加 | 8+4 | 12 |
- | 減 | 8-4 | 4 |
* | 乘 | 8*4 | 32 |
\ | 除 | 8\2 | 4 |
% | 取模(求餘) | 9 % 4 | 1 |
++ | 自增(變量前) | i=4;m=++i; | i爲5,m爲5 |
++ | 自增(變量後) | i=4;m=i++; | i爲5,m爲4 |
– | 自減(變量前) | i=4;m=–i; | i爲3,m爲3 |
– | 自減(變量後) | i=4;m=i–; | i爲3,m爲4 |
大多數運算都和數學所學相同,不再贅述。着重介紹除法和自增自減運算。
注意:在Java中,實數(float和double類型)是可以進行取模操作的。
除法和求餘
我們先來看一個程序(只顯示主方法內的代碼):
public class Arithmetic01 {
public static void main(String[] args) {
System.out.println("8/4="+8/4);//數學計算中結果爲2,結果爲2
System.out.println("9/4="+9/4);//數學計算中結果爲2.25,結果爲2
System.out.println("11/4="+11/4);//數學計算中結果爲2.75,結果爲2
System.out.println("11.0/4="+11.0/4);//數學計算中結果爲2.75,結果爲2.75
System.out.println("11%4="+11%4);//餘數爲3
System.out.println("11.5%3.5="+11.5%3.5);//餘數爲1.0
}
}
運行結果爲:
8/4=2
9/4=2
11/4=2
11.0/4=2.75
11%4=3
11.5%3.2=1.0
通過這個程序,我們可以看到,8除以4結果爲2,這符合我們的預期;但9除以4和11除以4,結果均只有整數部分,這就是整數除法的特點:整數除以整數,結果還是整數。
如果我們希望得到期望中的小數,將除法運算中任何一個數改爲實數類型即可。
這個特性是由計算機中整數的存儲和處理方法決定的,因此我們在使用除法時一定要特別注意。
此外,在Java中,實數(float和double類型)是可以進行取模操作的。
自增和自減
自增、自減,顧名思義,就是爲使用這個運算的變量自身增加1或者減少1。例如變量x原來的值是40,使用自增運算後,x的值爲41;如果變量x原來的值是40,使用自減運算後,x的值爲39。讓上面的表中,最令人迷惑的就是:當自增|自減運算是其它運算的一部分時,變量和自增|自減運算的位置不同,會導致最終結果的不同。由於自增和自減的規則相同,所以下面這個例子中只使用了自增運算:
public class Arithmetic02 {
public static void main(String[] args) {
int x = 10;
int y;
System.out.println("x=" + x);//x的初始值爲10
x++;
System.out.println("進行x++運算後,x=" + x);//自增運算一次,x值爲11
++x;
System.out.println("進行++x運算後,x=" + x);//再自增運算一次,x值爲12
//先提取x的值進行賦值運算,再進行自增運算
System.out.println("x+++y=" + (x+++y)+",x="+x+",y="+y);
//先進行自增運算,再提取x的值進行賦值運算
System.out.println("++x+y=" + (++x+y)+",x="+x+",y="+y);
}
}
運行結果是:
x=10,y=20
進行x++運算後,x=11
進行++x運算後,x=12
x+++y=32,x=13,y=20
++x+y=34,x=14,y=20
通過這個例子,不難總結:如果自增|自減運算是單獨進行的,那麼變量和運算符的位置關係不影響最終結果;如果自增|自減運算是其它運算中的一部分,那麼變量在前面時,就先把變量的值代入到整個運算中,運算完畢後再進行自增|自減運算,運算符在前面時,就先進行自增|自減運算,然後把結果代入到整個運算中。
賦值運算
賦值運算我們一直在用,前面的程序中:int x=10;
。這可不能讀作“整型變量x等於10”,而是“把10賦給整型變量x”。這個=
在數學上是“等號”,但在Java中是“賦值運算符”,它的作用是把運算符右邊的值賦給左邊的變量。所以:
- 賦值運算是從右向左進行的。
a=a+1
這樣的代碼在執行時,就會先把右邊的變量a的值提取出來,加1,再將和存入到變量a中。同時,代碼int a,b,c;a=b=c=10;
是正確的,因爲從右向左賦值;但int a=b=c=10;
是錯誤的,因爲10先賦給了c,但c還沒有定義。 - 右邊必須是一個確定的值或能求出確定值的運算式,左邊則必須、只能是個變量
爲了簡化代碼,還有以下賦值運算符:
運算符 | 說明 | 示例 | 相當於 |
---|---|---|---|
+= | 加等於 | a+=3 | a=a+3 |
-= | 減等於 | a-=3 | a=a-3 |
*= | 乘等於 | a*=3 | a=a*3 |
\= | 除等於 | a\=3 | a=a\3 |
%= | 模等於 | a%=3 | a=a |
02
比較運算
在Java中可以對兩個數值進行大小比較,其結果爲一個布爾值,true表示比較成立,false表示不成立。比較運算包括:
運算符 | 說明 | 示例 | 結果 |
---|---|---|---|
== | 等於 | 50==23 | false |
!= | 不等於 | 50!=23 | true |
> | 大於 | 50>23 | true |
< | 小於 | 50<23 | true |
>= | 大於等於 | 50>=23 | true |
<= | 小於等於 | 50<=23 | true |
大家可以編寫並運行以下程序(只顯示主要部分):
public class Compare {
public static void main(String[] args) {
System.out.println("50==23?"+(50==23));
System.out.println("50!=23?"+(50!=23));
System.out.println("50>23?"+(50>23));
System.out.println("50<23?"+(50<23));
System.out.println("50>=23?"+(50>=23));
System.out.println("50<=23?"+(50<=23));
}
}
結果爲:
50==23?false
50!=23?true
50>23?true
50<23?false
50>=23?true
50<=23?false
邏輯運算
邏輯運算是針對邏輯值(布爾類型)的運算,其結果還是一個布爾類型的值。邏輯運算包括:
運算符 | 說明 | 示例 | 結果 |
---|---|---|---|
&和&& | 與 | a&b(a&&b) | 當a和b均爲true時,結果爲true,其他情況均爲false |
| 和 || | 或 | a|b(a||b) | 當a和b均爲false時,結果爲false,其他情況均爲true |
! | 非 | !a | 取相反值,a爲true時,!a爲false;a爲false時,!a爲true |
^ | 異或 | a^b | a、b值相同時爲false,不相同時爲true |
與和或運算均出現了兩個符號。其中,&和|中包含其它運算時,所有的運算都會被執行;&&和||中包含其它運算時,如果在不完成所有運算的情況下就能得出結論,那麼不再執行剩下的運算。
由於短路與和短路或情況類似,我們這裏只看短路或的例子。對於短路與,大家可以編寫下面的程序:
public class LogicDemo {
public static void main(String[] args) {
int a=100;
int b=200;
boolean c=true;
boolean d=false;
System.out.println("邏輯或:"+(c|d));
System.out.println("邏輯與:"+(c&d));
System.out.println("邏輯異或:"+(c^d));
System.out.println("邏輯非:"+(!c));
System.out.println("使用普通或運算:");
System.out.println((a>20)|(++b>500));//a>20值爲true,++b>500值爲false,同時b自增1,結果爲true
System.out.println("b="+b);//輸出b的值,爲201
System.out.println("使用短路或運算:");
System.out.println("計算(a>20)||(++b>500):"+((a>20)||(++b>500)));//a>20值爲true,此時已經可以確定最終結果,++b>500沒有執行
System.out.println("b="+b);//輸出b的值,爲201
System.out.println("計算(a<20)||(++b>500):"+((a<20)||(++b>500)));//a<20值爲false,此時不能確定最終結果,++b>500需要執行
System.out.println("b="+b);//輸出b的值,爲202
}
}
運行結果爲:
邏輯或:true
邏輯與:false
邏輯異或:true
邏輯非:false
使用普通或運算:
true
b=201
使用短路或運算:
計算(a>20)||(++b>500):true
b=201
計算(a<20)||(++b>500):false
b=202
其它運算大家可以自己寫程序進行驗證和練習。
位運算
位運算只能用於整型數據,而且只能在二進制層面進行運算。整型數據在計算機中是以二進制形式存儲,位運算也是針對二進制數據進行的運算。主要包括:
運算符 | 說明 | 示例 | 結果 |
---|---|---|---|
& | 按位與 | a&b | 參與運算的兩位都是1,結果爲1,其餘爲0 |
| | 按位或 | a|b | 參與運算的兩位都是0,結果爲0,其餘爲1 |
~ | 取反 | ~a | 1變爲0,0變爲1 |
^ | 異或 | a^b | 參與運算的兩位相同爲0,不同爲1 |
<< | 左移 | a<<2 | 二進制數據向左移動2位,右端補0 |
>> | 右移 | a>>2 | 二進制數據向右移動2位,正數左端補0,負數補1 |
>>> | 無符號右移 | a>>>2 | 二進制數據向右移動2位,無論正負均補0 |
在與、或、異或的位運算中,參與運算的兩個數必須是二進制形式,右對齊,左邊不足補0,從右向左進行計算。例如:
10011001
& 00001101
----------
00001001
取反時,將二進制的1轉換爲0,0轉換爲1。需要注意的是,由於正整數和負整數在內存中的表示方法不同,對十進制的整數1
進行取反操作,結果是-2
,而不是0。
左移時,將最左邊的數據移出變量的存儲空間,右側補0。如果左移時,沒有1被移出存儲空間,每左移一位,就相當於乘以一次2。
右移時,將最右邊的數據移出變量的存儲空間,但由於最左邊那一位是符號位,左邊補0還是1,產生兩種處理方式:一是正數補0,負數補1,即>>
;二是無論正負,一律補0,即>>>
。
大家可以編寫並運行以下程序,思考一下具體執行過程:
public class BitOperate {
public static void main(String[] args) {
int a=1;//二進制形式爲01,省略了前面30字位的0
int b=3;//二進制形式爲11,省略了前面30字位的0
System.out.println("a&b="+(a&b));//01&11=01,十進制的1
System.out.println("a|b="+(a|b));//01|11=11,十進制的3
System.out.println("a^b="+(a^b));//01^11=10,十進制的2
System.out.println("~a="+(~a));//~01=10,前面30字位的0也要取反爲1,所以實際答案是11111111111111111111111111111110,-2
System.out.println("a<<2="+(a<<2));//a左移兩位,爲4
System.out.println("-a<<2="+((-a)<<2));//-a,即-1左移兩位,爲-4
System.out.println("b>>1="+(b>>1));//b右移1位,爲1
System.out.println("-b>>1="+((-b)>>1));//-b右移1位,爲-2
System.out.println("b>>>1="+(b>>>1));//b無符號右移1位,爲1
System.out.println("-b>>>1="+((-b)>>>1));//-b無符號右移1位,爲2147483646
}
}
條件運算
Java中還有一個條件運算,也是Java唯一一個三目運算符(這個運算涉及到三個參數)。它的格式是:表達式1?表達式2:表達式3
。
表達式1必須是邏輯表達式——其自身或者運算結果必須是個邏輯值,true或者false。如果表達式1的值是true,整個運算的結果就是表達式2的值;如果表達式1的值是false,整個運算的結果就是表達式3的值。也就是說,條件運算可以根據條件的不同(表達式1的值),來產生不同的結果(表達式2和表達式3的值)。
我們來看這個程序:
public class SelectiveOperation {
public static void main(String[] args) {
int a=300;
int b=500;
byte score=90;
System.out.println("a和b中:"+(a>b?"a比較大":"b比較大"));
System.out.println("你的考試成績:"+(score>=60?"及格":"不及格"));
}
}
02
數據類型轉換
之前我們提到,9/4=2
,這是由於計算機中不同數據類型的保存和處理方法是不同的。這就帶來一個問題,當不同類型的數據放到一起進行運算時,該如何處理?
答案是通過數據類型轉換,把不同類型的數據轉換爲相同的數據類型,再進行運算。
具體轉換方法這裏不進行深入探討,我們主要學習在什麼情況下使用哪種轉換方式。
在Java中,有兩種數據類型轉換方式:自動類型轉換和強制類型轉換。
自動類型轉換
顧名思義,不需要我們手工干預就可以完成。一般來說,當兩個不同類型的數據在一起運算時,表示範圍小、精度低的數據類型會轉換爲表示範圍大、精度高的類型。
轉換規律爲:
(byte,short,char)–>int–>long–>float–>double
byte,short和char三種類型都會轉換爲int類型——即使運算中不包含int類型時也是如此,例如兩個short類型數據在一起運算。
強制類型轉換
我們有時需要手工指定轉換目標,例如把表示範圍大、精度高的類型轉換爲範圍小、精度低的類型。轉換方法:(目標數據類型)轉換對象
,例如:(int)3.14
;這會把3.14(double類型)強制轉換爲int類型,結果爲3。
不過有時也需要強制把表示範圍小、精度低的類型會轉換爲表示範圍大、精度高的類型,例如在計算平均分時,我們需要用總分除以人數。人數必然是整數,分數很多時候也是分數,很容易在無意間寫成兩個整數相除,結果必然還是整數。我們可以把計算平均分的方法寫成:
//avg方法用於計算平均分,sum表示總分,num表示人數
double avg(int sum,int num){
return (double)sum/num;
}
在這個方法中,sum會被強制轉換爲double類型,那麼結果自然也是double類型了。
需要注意的是:除了
=
之外的所有賦值運算符,都會在需要時自動進行強制類型轉換。如:short s=50; int i=100; s+=i;
我們看這個對類型轉換進行總結的程序:
public class DTConversion {
public static void main(String[] args) {
//整數的自動類型轉換
byte b=34;
short s=23;
s=(short)(s+b);//自動轉換時,short數據和byte數據相加,會轉換爲int數據,所以不能直接賦值給short變量
System.out.println("自動進行強制轉換:"+(s+=b));//這種形式的賦值運算會自動進行強制轉換
System.out.println("不轉換:"+(12/5));
System.out.println("自動類型轉換:"+(12.0/5));
System.out.println("強制類型轉換:"+((double)12/5));
System.out.println("強制轉換可能會導致精度損失:"+(int)12.5);
}
}
運算符的優先級
Java中包含了很多運算符,當這些運算符在同一個運算式中時,必須規定執行順序,這就是優先級。Java中運算符的優先級是這樣規定的:
優先級 | 運算符 | 結合性 |
---|---|---|
1 | .、()、[]、{} | 從左向右 |
2 | !、+、-、~、++、– | 從右向左 |
3 | *、/、% | 從左向右 |
4 | +、-(正負號) | 從左向右 |
5 | <<、 >>、 >>> | 從左向右 |
6 | <、 <=、 >、>=、instanceof | 從左向右 |
7 | ==、!= | 從左向右 |
8 | & | 從左向右 |
9 | ^ | 從左向右 |
10 | | | 從左向右 |
11 | && | 從左向右 |
12 | || | 從左向右 |
13 | ?: | 從右向左 |
14 | =、+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、~=、^=、|= | 從右向左 |
由於小括號的優先級非常高,因此,如果暫時記不住這個表,那麼可以用小括號把需要先計算的部分括起來。但仍需要通過記憶和練習,記住他們的優先級的。
02