教妹學Java第11講:Java 運算符
同學們好啊,我是沉默王二,一枚沉默但有趣又帥氣的程序員。又到了《教妹學 Java》的時間,很開心,很期待,很舒適。這是《教妹學 Java》專欄的第 11 篇文章,我們來談談“Java 運算符”。
強烈推薦:我在 GitHub 上發(fā)現(xiàn)了一個寶藏項目,里面 搜集了 500 百本電子書,包含 Java 入門、Spring 框架、MySQL 數(shù)據(jù)庫、性能優(yōu)化、設計模式、計算機網(wǎng)絡、操作系統(tǒng)、數(shù)據(jù)結構與算法、面試刷題、大數(shù)據(jù)、架構等等方面,應有盡有,需要的小伙伴可以到 GitHub 或者碼云上獲取。
GitHub:https://github.com/itwanger/JavaBooks
碼云:https://gitee.com/itwanger/JavaBooks
上一篇文章發(fā)表后,就有同學留言說“妹妹大一就開始學習 Java 了,有點厲害啊?!蔽抑荒苷f,必須從嚴治妹,要對她負責任,就必須得趁早。

強調(diào)一下,《教妹學 Java》面向的是零基礎的 Java 愛好者,我希望能幫助同學們輕松邁進編程世界的大門,為后續(xù)的深入學習打下堅實的基礎。

-------------------------------正兒八經(jīng)的分割線-------------------------------
“二哥,讓我盲猜一下哈,運算符是不是指的就是加減乘除???”三妹的臉上泛著甜甜的笑容,我想她一定對提出的問題很有自信。
“是的,三妹。運算符在 Java 中占據(jù)著重要的位置,對程序的執(zhí)行有著很大的幫助。除了常見的加減乘除,還有許多其他類型的運算符,來看下面這張思維導圖?!?/p>
01、算數(shù)運算符
算術運算符除了最常見的加減乘除,還有一個取余的運算符,用于得到除法運算后的余數(shù),來串代碼感受下。
/**
?*?微信搜索「沉默王二」,回復?Java
?*/
public?class?ArithmeticOperator?{
????public?static?void?main(String[]?args)?{
????????int?a?=?10;
????????int?b?=?5;
????????System.out.println(a?+?b);//15
????????System.out.println(a?-?b);//5
????????System.out.println(a?*?b);//50
????????System.out.println(a?/?b);//2
????????System.out.println(a?%?b);//0
????????b?=?3;
????????System.out.println(a?+?b);//13
????????System.out.println(a?-?b);//7
????????System.out.println(a?*?b);//30
????????System.out.println(a?/?b);//3
????????System.out.println(a?%?b);//1
????}
}
對于初學者來說,加法(+)、減法(-)、乘法(*)很好理解,但除法(/)和取余(%)會有一點點疑惑。在以往的認知里,10/3 是除不盡的,結果應該是 3.333333...,而不應該是 3。相應的,余數(shù)也不應該是 1。這是為什么呢?
因為數(shù)字在程序中可以分為兩種,一種是整形,一種是浮點型(不清楚的同學可以回頭看看數(shù)據(jù)類型那篇),整形和整形的運算結果就是整形,不會出現(xiàn)浮點型。否則,就會出現(xiàn)浮點型。
/**
?*?微信搜索「沉默王二」,回復?Java
?*/
public?class?ArithmeticOperator?{
????public?static?void?main(String[]?args)?{
????????int?a?=?10;
????????float?c?=?3.0f;
????????double?d?=?3.0;
????????System.out.println(a?/?c);?//?3.3333333
????????System.out.println(a?/?d);?//?3.3333333333333335
????????System.out.println(a?%?c);?//?1.0
????????System.out.println(a?%?d);?//?1.0
????}
}
需要注意的是,當浮點數(shù)除以 0 的時候,結果為 Infinity 或者 NaN。
System.out.println(10.0?/?0.0);?//?Infinity
System.out.println(0.0?/?0.0);?//?NaN
Infinity 的中文意思是無窮大,NaN 的中文意思是這不是一個數(shù)字(Not a Number)。
當整數(shù)除以 0 的時候(10 / 0),會拋出異常:
Exception?in?thread?"main"?java.lang.ArithmeticException:?/?by?zero
?at?com.itwanger.eleven.ArithmeticOperator.main(ArithmeticOperator.java:32)
所以整數(shù)在進行除法運算時,需要先判斷除數(shù)是否為 0,以免程序拋出異常。
算術運算符中還有兩種特殊的運算符,自增運算符(++)和自減運算符(--),它們也叫做一元運算符,只有一個操作數(shù)。
public?class?UnaryOperator1?{
????public?static?void?main(String[]?args)?{
????????int?x?=?10;
????????System.out.println(x++);//10?(11)??
????????System.out.println(++x);//12??
????????System.out.println(x--);//12?(11)??
????????System.out.println(--x);//10??
????}
}
一元運算符可以放在數(shù)字的前面或者后面,放在前面叫前自增(前自減),放在后面叫后自增(后自減)。
前自增和后自增是有區(qū)別的,拿 int y = ++x 這個表達式來說(x = 10),它可以拆分為 x = x+1 = 11; y = x = 11,所以表達式的結果為 x = 11, y = 11。拿 int y = x++ 這個表達式來說(x = 10),它可以拆分為 y = x = 10; x = x+1 = 11,所以表達式的結果為 x = 11, y = 10。
int?x?=?10;
int?y?=?++x;
System.out.println(y?+?"?"?+?x);//?11?11
x?=?10;
y?=?x++;
System.out.println(y?+?"?"?+?x);//?10?11
對于前自減和后自減來說,同學們可以自己試一把。
02、關系運算符
關系運算符用來比較兩個操作數(shù),返回結果為 true 或者 false。

來看示例:
/**
?*?微信搜索「沉默王二」,回復?Java
?*/
public?class?RelationOperator?{
????public?static?void?main(String[]?args)?{
????????int?a?=?10,?b?=?20;
????????System.out.println(a?==?b);?//?false
????????System.out.println(a?!=?b);?//?true
????????System.out.println(a?>?b);?//?false
????????System.out.println(a?//?true
????????System.out.println(a?>=?b);?//?false
????????System.out.println(a?<=?b);?//?true
????}
}
03、位運算符
在學習位運算符之前,需要先學習一下二進制,因為位運算符操作的不是整形數(shù)值(int、long、short、char、byte)本身,而是整形數(shù)值對應的二進制。
/**
?*?微信搜索「沉默王二」,回復?Java
?*/
public?class?BitOperator?{
????public?static?void?main(String[]?args)?{
????????System.out.println(Integer.toBinaryString(60));?//?111100
????????System.out.println(Integer.toBinaryString(13));?//?1101
????}
}
從程序的輸出結果可以看得出來,60 的二進制是 0011 1100(用 0 補到 8 位),13 的二進制是 0000 1101。
PS:現(xiàn)代的二進制記數(shù)系統(tǒng)由戈特弗里德·威廉·萊布尼茨于 1679 年設計。萊布尼茨是德意志哲學家、數(shù)學家,歷史上少見的通才。

來看示例:
/**
?*?微信搜索「沉默王二」,回復?Java
?*/
public?class?BitOperator?{
????public?static?void?main(String[]?args)?{
????????int?a?=?60,?b?=?13;
????????System.out.println("a 的二進制:"?+?Integer.toBinaryString(a));?//?111100
????????System.out.println("b 的二進制:"?+?Integer.toBinaryString(b));?//?1101
????????int?c?=?a?&?b;
????????System.out.println("a & b:"?+?c?+?",二進制是:"?+?Integer.toBinaryString(c));
????????c?=?a?|?b;
????????System.out.println("a | b:"?+?c?+?",二進制是:"?+?Integer.toBinaryString(c));
????????c?=?a?^?b;
????????System.out.println("a ^ b:"?+?c?+?",二進制是:"?+?Integer.toBinaryString(c));
????????c?=?~a;
????????System.out.println("~a:"?+?c?+?",二進制是:"?+?Integer.toBinaryString(c));
????????c?=?a?<2;
????????System.out.println("a << 2:"?+?c?+?",二進制是:"?+?Integer.toBinaryString(c));
????????c?=?a?>>?2;
????????System.out.println("a >> 2:"?+?c?+?",二進制是:"?+?Integer.toBinaryString(c));
????????c?=?a?>>>?2;
????????System.out.println("a >>> 2:"?+?c?+?",二進制是:"?+?Integer.toBinaryString(c));
????}
}
對于初學者來說,位運算符無法從直觀上去計算出結果,不像加減乘除那樣。因為我們?nèi)粘=佑|的都是十進制,位運算的時候需要先轉成二進制,然后再計算出結果。
鑒于此,初學者在寫代碼的時候其實很少會用到位運算。對于編程高手來說,為了提高程序的性能,會在一些地方使用位運算。比如說,HashMap 在計算哈希值的時候:
static?final?int?hash(Object?key)?{
????int?h;
????return?(key?==?null)???0?:?(h?=?key.hashCode())?^?(h?>>>?16);
}
如果對位運算一點都不懂的話,遇到這樣的源碼就很吃力。所以說,雖然位運算用的少,但還是要懂。
1)按位左移運算符:
public?class?LeftShiftOperator?{
????public?static?void?main(String[]?args)?{
????????System.out.println(10<<2);//10*2^2=10*4=40??
????????System.out.println(10<<3);//10*2^3=10*8=80??
????????System.out.println(20<<2);//20*2^2=20*4=80??
????????System.out.println(15<<4);//15*2^4=15*16=240??
????}
}
10<<2 等于 10 乘以 2 的 2 次方;10<<3 等于 10 乘以 2 的 3 次方。
2)按位右移運算符:
public?class?RightShiftOperator?{
????public?static?void?main(String[]?args)?{
????????System.out.println(10>>2);//10/2^2=10/4=2
????????System.out.println(20>>2);//20/2^2=20/4=5
????????System.out.println(20>>3);//20/2^3=20/8=2
????}
}
10>>2 等于 10 除以 2 的 2 次方;20>>2 等于 20 除以 2 的 2 次方。
04、邏輯運算符
邏輯與運算符(&&):多個條件中只要有一個為 false 結果就為 false。
邏輯或運算符(||):多個條件只要有一個為 true 結果就為 true。
public?class?LogicalOperator?{
????public?static?void?main(String[]?args)?{
????????int?a=10;
????????int?b=5;
????????int?c=20;
????????System.out.println(a//false?&&?true?=?false
????????System.out.println(a>b||a//true?||?true?=?true
????}
}
邏輯非運算符(|):用來反轉條件的結果,如果條件為 true,則邏輯非運算符將得到 false。
單邏輯與運算符(&):很少用,因為不管第一個條件為 true 還是 false,依然會檢查第二個。
單邏輯或運算符(|):也會檢查第二個條件。
也就是說,& 和 | 性能不如 && 和 ||,但用法一樣:
public?class?LogicalOperator1?{
????public?static?void?main(String[]?args)?{
????????int?a=10;
????????int?b=5;
????????int?c=20;
????????System.out.println(a//false?&?true?=?false
????????System.out.println(a>b|a//true?|?true?=?true??
????}
}
05、賦值運算符
賦值操作符恐怕是 Java 中使用最頻繁的操作符了,它就是把操作符右側的值賦值給左側的變量。來看示例:
public?class?AssignmentOperator?{
????public?static?void?main(String[]?args)?{
????????int?a=10;
????????int?b=20;
????????a+=4;//a=a+4?(a=10+4)??
????????b-=4;//b=b-4?(b=20-4)??
????????System.out.println(a);
????????System.out.println(b);
????}
}
不過在進行數(shù)值的賦值時,需要小點心,比如說下面這種情況:

編譯器之所以提示錯誤,是因為 = 右側的算術表達式默認為 int 類型,左側是 short 類型的時候需要進行強轉。
public?class?AssignmentOperator1?{
????public?static?void?main(String[]?args)?{
????????short?a?=?10;
????????short?b?=?10;
//a+=b;//a=a+b?internally?so?fine
????????a?=?(short)(a?+?b);
????????System.out.println(a);
????}
}
除此之外,還會有邊界問題,比如說,兩個非常大的 int 相乘,結果可能就超出了 int 的范圍:
/**
?*?微信搜索「沉默王二」,回復?Java
?*/
public?class?BigIntMulti?{
????public?static?void?main(String[]?args)?{
????????int?a?=?Integer.MAX_VALUE;
????????int?b?=?10000;
????????int?c?=?a?*?b;
????????System.out.println(c);?//?-10000
????}
}
程序輸出的結果為 -10000,這個答案很明顯不是我們想要的結果,雖然可以通過右側表達式強轉 long 的方法解決:
/**
?*?微信搜索「沉默王二」,回復?Java
?*/
public?class?BigIntMulti?{
????public?static?void?main(String[]?args)?{
????????int?a?=?Integer.MAX_VALUE;
????????int?b?=?10000;
????????long?c?=?(long)a?*?b;
????????System.out.println(c);?//?21474836470000
????}
}
但盡量不要這樣做,結果非常大的時候,盡量提前使用相應的類型進行賦值。
long?a?=?Integer.MAX_VALUE?-?1;
long?b?=?10000;
long?c?=?a?*?b;
System.out.println(c);?//?21474836460000
06、三元運算符
三元運算符用于替代 if-else,可以使用一行代碼完成條件判斷的要求。來看示例:
public?class?TernaryOperator?{
????public?static?void?main(String[]?args)?{
????????int?a=2;
????????int?b=5;
????????int?min=(a????????System.out.println(min);
????}
}
如果 ? 前面的條件為 true,則結果為 : 前的值,否則為 : 后的值。
“好了,三妹,關于 Java 運算符就先說這么多吧,你是不是已經(jīng)清楚了?”轉動了一下僵硬的脖子后,我對三妹說。
“差不多,二哥,我需要寫點 demo 練習會?!?/p>
這是《教妹學 Java》專欄的第 11 篇文章,能看到這里的小伙伴都是最帥的,最美的,升職加薪就是你了?。

寫這個專欄的初衷就是為了幫助那些零基礎學 Java,或者自學 Java 感覺特別痛苦,特別難入門的小伙伴。
另外,我還創(chuàng)建了一些「技術交流群」,群里氛圍很不錯,有不少小伙伴會分享一些校招或者社招經(jīng)驗,更重要的是,群里時不時會有「紅包」等福利,當然,群里不允許任何形式的廣告。掃描下方的二維碼,回復「加群」即可。
示例代碼已經(jīng)同步到 GitHub,地址為 github.com/itwanger,也可以點擊閱讀原文進行跳轉,歡迎 star。
