碼字不易,對(duì)你有幫助 點(diǎn)贊/轉(zhuǎn)發(fā)/關(guān)注 支持一下作者
微信搜公眾號(hào):不會(huì)編程的程序圓
看更多干貨,獲取第一時(shí)間更新
如果想看更好的排版,可以閱讀原文
點(diǎn)擊閱讀原文
思維導(dǎo)圖
目錄
@[toc]
正文
前言
在正式開始講 運(yùn)算符 之前,我們先來(lái)討論一下上節(jié)課我們所學(xué)的 變量 的一個(gè)注意點(diǎn)。
- byte 與 char
- short 與 char
上面兩組類型之間的轉(zhuǎn)換不管是從小到大還是從大到小,都需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。
public class helloWorld{
public static void main(String[] args) {
byte bt = 10;// byte 類型大小為 1 個(gè)字節(jié)
char ch = ' ';// char 類型大小為 2 個(gè)字節(jié)
short sh = 10;// short 類型大小為 2 個(gè)字節(jié)
ch = bt;// 將 1 個(gè)字節(jié)的 bt 賦值給 2 個(gè)字節(jié)的 ch
//編譯會(huì)報(bào)錯(cuò):不兼容的類型: 從byte轉(zhuǎn)換到char可能會(huì)有損失
ch = sh;
sh = ch;
//編譯器還是會(huì)報(bào)錯(cuò):不兼容的類型:從short/char轉(zhuǎn)換到char/short可能會(huì)有損失
}
}
原因:
1、char 是字符型,而 byte 和 short 是數(shù)值型,他們之間不建議轉(zhuǎn)換。
2、char 類型字符對(duì)應(yīng)的 十進(jìn)制 是沒有負(fù)數(shù)的。
一 運(yùn)算符
1. 算術(shù)運(yùn)算符
+
-
*
/
%
注意:
-
int / int 結(jié)果還是 int, 需要使用 double 來(lái)計(jì)算
int a = 1; int b = 2; System.out.println(a / b); // 結(jié)果為 0如何正確的輸出我們想要的 0.5 呢?
//以下三種方式得到的結(jié)果都是 0.5 System.out.println(1.0 / 2); System.out.println(1 / 2.0); System.out.println(1.0 / 2.0);需要注意的是,在 1.0 / 2 時(shí),1.0 無(wú)疑是 double 類型,在運(yùn)算時(shí) 2 也會(huì)被提升為 double 類型,也就是 1.0 / 2.0
-
0 不能作為除數(shù)
int a = 1; int b = 0; System.out.println(a / b) // 運(yùn)行結(jié)果 Exception in thread "main" java.lang.ArithmeticException: / by zero at Test.main(Test.java:5) -
% 表示取余,不僅僅可以對(duì) int 求模,也能對(duì) double 來(lái)求模
System.out.println(11.5 % 2.0); //運(yùn)行結(jié)果 1.5 -
% 的操作數(shù)出現(xiàn)負(fù)數(shù)
System.out.println(5 % 2); System.out.println(5 % -2); System.out.println(-5 % -2); System.out.println(-5 % -2); //運(yùn)行結(jié)果 1 1 -1 -1我們?cè)?【C語(yǔ)言必知必會(huì)】的【C語(yǔ)言入門到精通】的運(yùn)算符一節(jié)中討論過這個(gè)問題。
簡(jiǎn)單的來(lái)說(shuō),結(jié)果正負(fù)取決于 左操作數(shù) 的正負(fù)。
+=
-=
*=
/=
%=
int a = 10;
a += 1; // 等價(jià)于 a = a + 1
System.out.println(a);
//運(yùn)行結(jié)果
11
++
--
int a = 10;
int b = ++a;
System.out.println(b);
int c = a++;
System.out.println(c);
//運(yùn)行結(jié)果
11
11
結(jié)論:
- 如果不取自增運(yùn)算的表達(dá)式的返回值, 則前置自增和后置自增沒有區(qū)別。
- 如果取表達(dá)式的返回值, 則前置自增的返回值是自增之后的值, 后置自增的返回值是自增之前的值。
思考題:下面程序會(huì)輸出什么?
int i = 10;
i = i++;
System.out.println(i);
2. 關(guān)系運(yùn)算符
==
!=
<
>
>=
<=
int a = 10;
int b = 20;
System.out.println(a == b);
System.out.println(a != b);
System.out.println(a < b);
System.out.println(a > b);
System.out.println(a <= b);
System.out.println(a >= b);
//運(yùn)行結(jié)果
false
true
true
false
true
false
注意: 關(guān)系運(yùn)算符的表達(dá)式返回值都是 boolean 類型。
3. 邏輯運(yùn)算符
注意: 邏輯運(yùn)算符的操作數(shù)(操作數(shù)往往是關(guān)系運(yùn)算符的結(jié)果)和返回值都是 boolean 。
這一點(diǎn)是和 C 語(yǔ)言不同的地方:
int a = 1, b = 2;
System.out.println(a && b);
//編譯錯(cuò)誤
helloWorld.java:7: 錯(cuò)誤: 二元運(yùn)算符 '&&' 的操作數(shù)類型錯(cuò)誤
System.out.println(a && b);
^
應(yīng)當(dāng)做出如下修改:
boolean flag1 = false, flag2 = false;
System.out.println(flag1 && flag2);
//運(yùn)行結(jié)果:
false
邏輯運(yùn)算符主要有三個(gè):
&&
||
!
邏輯與 &&
規(guī)則: 兩個(gè)操作數(shù)都為 true, 結(jié)果為 true, 否則結(jié)果為 false 。
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b && b < c);
//運(yùn)行結(jié)果
true
邏輯或 ||
規(guī)則: 兩個(gè)操作數(shù)都為 true, 結(jié)果為 true, 否則結(jié)果為 false 。
int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b || b > c)
//運(yùn)行結(jié)果
true
邏輯非 !
規(guī)則: 操作數(shù)為 true, 結(jié)果為 false; 操作數(shù)為 false, 結(jié)果為 true(這是個(gè)單目運(yùn)算符, 只有一個(gè)操作數(shù))
int a = 10;
int b = 20;
System.out.println(!a < b);
//編譯錯(cuò)誤
! 只能作用于 boolean 類型,而 a 是 int 類型
短路求值
&& 和 || 遵守短路求值的規(guī)則。
System.out.println(10 > 20 && 10 / 0 == 0);
System.out.println(10 < 20 || 10 / 0 == 0);
//打印結(jié)果:
false
true
我們都知道, 計(jì)算 10 / 0 會(huì)導(dǎo)致程序拋出異常。但是上面的代碼卻能正常運(yùn)行, 說(shuō)明 10 / 0 并沒有真正被求值。
結(jié)論:
- 對(duì)于 && ,如果左側(cè)表達(dá)式值為 false, 則表達(dá)式的整體的值一定是 false, 無(wú)需計(jì)算右側(cè)表達(dá)式
- 對(duì)于 || ,如果左側(cè)表達(dá)式值為 true, 則表達(dá)式的整體的值一定是 true, 無(wú)需計(jì)算右側(cè)表達(dá)式
**& 和 | (不推薦使用) **
& 和 | 如果操作數(shù)為 boolean 的時(shí)候, 也表示邏輯運(yùn)算. 但是和 && 以及 || 相比, 它們不支持短路求值
System.out.println(10 > 20 & 10 / 0 == 0); // 程序拋出異常
System.out.println(10 < 20 | 10 / 0 == 0); // 程序拋出異常
4、位運(yùn)算符
位運(yùn)算符主要有 4 個(gè):
&
|
~
^
位操作表示 按二進(jìn)制位運(yùn)算。計(jì)算機(jī)中都是使用二進(jìn)制來(lái)表示數(shù)據(jù)的(01構(gòu)成的序列), 按位運(yùn)算就是在按照二進(jìn)制位的
每一位依次進(jìn)行計(jì)算。(這與 C 語(yǔ)言基本相同,我們?cè)?C 的教程中也詳細(xì)講過,這里不做展開。)
按位與:&
如果兩個(gè)二進(jìn)制位都是 1, 則結(jié)果為 1, 否則結(jié)果為 0 。
int a = 10;//01010
int b = 20;//10100
System.out.println(a & b);
//運(yùn)行結(jié)果:
0
操作數(shù)有負(fù)數(shù)的情況
byte a = -1;//1111 1111
byte b = 13;//0000 1101
System.out.println(a & b);
//運(yùn)行結(jié)果:
13
byte a = -1;//1111 1111
byte b = -2;//1111 1110
System.out.println(a & b);
//運(yùn)行結(jié)果:
-2
這說(shuō)明,負(fù)數(shù)補(bǔ)碼的符號(hào)位是參數(shù) & 運(yùn)算的。
按位或:|
如果兩個(gè)二進(jìn)制位都是 0, 則結(jié)果為 0, 否則結(jié)果為 1 。
int a = 10;//01010
int b = 20;//10100
System.out.println(a | b);
//運(yùn)行結(jié)果
30(11110)
注意: 當(dāng) & 和 | 的操作數(shù)為整數(shù)(int, short, long, byte) 的時(shí)候, 表示按位運(yùn)算, 當(dāng)操作數(shù)為 boolean 的時(shí)候, 表示邏輯運(yùn)算 。
按位取反:~
如果該位為 0 則轉(zhuǎn)為 1, 如果該位為 1 則轉(zhuǎn)為 0 。
int a = 0xf;
System.out.printf("%x\n", ~a);
//運(yùn)行結(jié)果:
fffffff0
解析:
- 0x 前綴的數(shù)字為 十六進(jìn)制 數(shù)字. 十六進(jìn)制可以看成是二進(jìn)制的簡(jiǎn)化表示方式. 一個(gè)十六進(jìn)制數(shù)字對(duì)應(yīng) 4 個(gè)二進(jìn)
制位. - 0xf 表示 10 進(jìn)制的 15, 也就是二進(jìn)制的 1111
- printf 能夠格式化輸出內(nèi)容, %x 表示按照十六進(jìn)制輸出(在 C 語(yǔ)言中,轉(zhuǎn)換說(shuō)明 x 表示以十六進(jìn)制打印 unsigned int 類型的值,unsigned int 是 4 個(gè) 字節(jié),Java 中雖然沒有 unsigned int 但是 %x 應(yīng)該同 C 一樣打印 4 個(gè)字節(jié)。所以,a 雖然是 0xf, 但是被編譯器看作是:0x0000000f )。
- \n 表示換行符
按位異或:^
如果兩個(gè)數(shù)字的二進(jìn)制位相同, 則結(jié)果為 0, 相異則結(jié)果為 1 。
byte a = 10;//1010
byte b = 14;//1110
System.out.println(a ^ b);
//運(yùn)行結(jié)果:
4(0010)
5、移位運(yùn)算(了解)
如果你想搞明白,可以去看看我的 C 語(yǔ)言的操作符的文章 和 【C進(jìn)階】第一節(jié)數(shù)據(jù)存儲(chǔ)。
<<
>>
>>>
左移:<<
最左側(cè)位不要了, 最右側(cè)補(bǔ) 0 。
int a = 0x10;
System.out.printf("%x\n", a << 1);
//運(yùn)行結(jié)果:(注意打印的格式是 16 進(jìn)制)
20(相當(dāng)于乘以 2)
右移:>>
最右側(cè)位不要了, 最左側(cè)補(bǔ)符號(hào)位(正數(shù)補(bǔ)0, 負(fù)數(shù)補(bǔ)1) 。
int a = 0x10;
//0x10 -> 16 -> 0001 0000 >> 1 -> 0000 1000 -> 8
System.out.printf("%x\n", a >> 1);
// 運(yùn)行結(jié)果
8(相當(dāng)于除以 2)
int b = 0xffff0000;//這是一個(gè)負(fù)數(shù)
System.out.printf("%x\n", b >> 1);
// 運(yùn)行結(jié)果
ffff8000
無(wú)符號(hào)右移:>>>
最右側(cè)位不要了, 最左側(cè)補(bǔ) 0 。
int a = -1;
System.out.println(a >> 1);
System.out.println(a >>> 1);
//運(yùn)行結(jié)果:
-1
2147483647
思考一下:
byte a = -1;
System.out.println(a >>> 1);//這樣會(huì)得到 127嗎?
//運(yùn)行結(jié)果:
2147483647
為什么會(huì)輸出這樣的值?
前面我們說(shuō)過,運(yùn)算過程中 byte,short 這類大小小于 4 個(gè)字節(jié)的類型會(huì)進(jìn)行數(shù)值提升,轉(zhuǎn)化為 int
那么這樣可以嗎?
byte a = -1;// 1111 1111
//a >>> 1 -> 0111 1111 1111 1111 1111 1111 1111 1111
byte b = (byte)(a >>> 1);
//知道了數(shù)值提升,我們這樣將運(yùn)算后的 int 轉(zhuǎn)化為 byte ,這樣可以得到正確結(jié)果嗎?
System.out.println(b);
//運(yùn)行結(jié)果:
-1
這是因?yàn)椋旱诙綇?qiáng)制類型轉(zhuǎn)換時(shí),int 會(huì)發(fā)生截?cái)?,byte 只得到 int 的后 8 位:1111 1111。在輸出 b 時(shí),1111 1111 還是會(huì)被當(dāng)作 -1 。這樣看似 >>> 操作符沒有什么卵用,但是我們應(yīng)該知道,在計(jì)算機(jī)內(nèi)部真實(shí)的情況。
總結(jié):
- 左移 1 位, 相當(dāng)于原數(shù)字 * 2. 左移 N 位, 相當(dāng)于原數(shù)字 * 2 的N次方。
- 右移 1 位, 相當(dāng)于原數(shù)字 / 2. 右移 N 位, 相當(dāng)于原數(shù)字 / 2 的N次方。
- 由于計(jì)算機(jī)計(jì)算移位效率高于計(jì)算乘除, 當(dāng)某個(gè)代碼正好乘除 2 的N次方的時(shí)候可以用移位運(yùn)算代替。
- 移動(dòng)負(fù)數(shù)位或者移位位數(shù)過大都沒有意義 。
6、條件運(yùn)算符
表達(dá)式1 ? 表達(dá)式2 : 表達(dá)式3
含義:當(dāng) 表達(dá)式1 的值為 true 時(shí), 整個(gè)表達(dá)式的值為 表達(dá)式2 的值; 當(dāng) 表達(dá)式1 的值為 false 時(shí), 整個(gè)表達(dá)式的值為 表達(dá)式3 的值
// 求兩個(gè)整數(shù)的最大值
int a = 10;
int b = 20;
int max = a > b ? a : b;
7、運(yùn)算符優(yōu)先級(jí)
運(yùn)算符之間是有優(yōu)先級(jí)的. 具體的規(guī)則我們不必記憶. 在可能存在歧義的代碼中加上括號(hào)即可 。
想看詳細(xì)的還是去看我 C 語(yǔ)言運(yùn)算符相關(guān)的教學(xué)。
總結(jié)
- % 操作再 Java 中也能針對(duì) double 來(lái)計(jì)算 。
- 需要區(qū)分清楚 前置自增 和 后置自增之間的區(qū)別 。
- 由于 Java 是強(qiáng)類型語(yǔ)言, 因此對(duì)于類型檢查較嚴(yán)格, 因此像 && 之類的運(yùn)算操作數(shù)必須是 boolean 。
- 要區(qū)分清楚 & 和 | 什么時(shí)候是表示按位運(yùn)算, 什么時(shí)候表示邏輯運(yùn)算 。
二 注釋
Java 的注釋方式和 C 一樣,主要有以下幾種:
//行注釋
/*這是
一個(gè)
塊注釋*/
/*
*這是
*文檔
*注釋
*/
三 關(guān)鍵字
與 C 語(yǔ)言相同,定義的 變量名 不能與 關(guān)鍵字 沖突。
| 用于定義訪問權(quán)限修飾符 | private | protected | public | ||
|---|---|---|---|---|---|
| 定義類,函數(shù),變量修飾符 | abstract | final | static | synchronized | |
| 定義類與類之間的關(guān)系 | extends | implements | |||
| 定義建立實(shí)例以及引用實(shí)例,判斷實(shí)例 | new | this | super | instanceof | |
| 用于異常處理 | try | catch | finally | throw | throws |
| 用于包 | package | import | |||
| 其他修飾符 | native | strictfp | transient | volatile | assert |
[0 基礎(chǔ)學(xué) java ] 系列的代碼可以在我的 Github 倉(cāng)庫(kù)查看,地址如下:
https://github.com/hairrrrr/Java_SE_EnjoyLearning
歡迎 star ?。c(diǎn)一個(gè) star 方便你下回查看)
本系列的教學(xué)也可以在 GitHub 觀看(GitHub 上看教學(xué)的好處是所有文章的目錄比較清晰)。
以上就是本次的內(nèi)容。
如果文章有錯(cuò)誤歡迎指正和補(bǔ)充,感謝!
最后,如果你還有什么問題或者想知道到的,可以在評(píng)論區(qū)告訴我呦,我可以在后面的文章加上你們的真知灼見。
關(guān)注我,看更多干貨!
我是程序圓,我們下次再見。