前言
運算符用于執行程式代碼運算,會針對一個以上操作數項目來進行運算。JAVA中常見的運算符有很多種,大緻分為以下幾種,常見的幾種運算符如下圖:
算術運算符 | 加、減、乘、除、求餘。例++、--、%、/、 |
指派運算符 | 為變量或常量起到指派作用的。例如=、+=、*= |
關系運算符 | 判斷資料大小的,結果為一個布爾值。例如>、>=、!=、== |
邏輯運算符 | 進行邏輯運算,運算的成員為布爾值,結果也為布爾值。例如&&、||、!。 |
條件運算符 | 也稱三目運算符,表達式為(a<b)?a:b |
位運算符 | 對二進制進行操作的,例如&、|、^、~、 |
一、算術運算符
1.1、常見的算術運算符
+ | 加法運算;例如x+y |
- | 減法運算;例如x-y |
* | 乘法運算;例如x*y |
/ | 除法運算;例如x/y 10/3=3; 10/2.0=5.0 |
% | 取模運算(求餘運算);例如x%y 10%3=1 |
++ | 自增運算;例如x++,++x |
-- | 自減運算;例如x--,--x |
1.2、算術運算中的類型轉換
我在我的上一篇部落格裡面詳細講解了關于JAVA基本資料類型的類型轉換了的,可以參考連結:https://blog.csdn.net/qq_37688023/article/details/85106894仔細看一下即可。不過在這裡大緻說一下其中幾個重要的點。
- 運算時,運算結果會向資料類型大的轉換;
- 在運算時,byte、short、char類型先自動轉換為int類型
@Test
public void a() {
int a=3;
double b=4;
System.out.println(a+b);//輸出7.0
float c=3.2f;
/*c=c+3.14; 編譯錯誤,運算之後變為double類型*/
byte a1=3;
byte b1=4;
/*byte c1=a+b;
* 編譯錯誤,此處由于byte類型參與運算時,先直接轉換為int類型,
* 是以最後的結果也是int類型,但是得出的結果不能叫做int類型的直接量,是以編譯錯誤
* */
int d1=a1+b1;
}
1.3、關于i++與++i的差別
- i++是++在後,是以先用了再加
- ++i是++在前,是以先加了再用
注意點:a+++b與a+ ++b的差別 a+++b的含義是(a++)+b;而a+ ++b的含義為a+(++b)
@Test
public void b() {
int a=1;
int b=1;
System.out.println(a++);//輸出1
System.out.println(++b);//輸出2
int a1=10;
int b1=10;
int sum=a1+++b1;
System.out.println(a1);//輸出11
System.out.println(b1);//輸出10
System.out.println(sum);//輸出20
int a2=10;
int b2=10;
int sum1=a2+ ++b2;
System.out.println(a2);//輸出10
System.out.println(b2);//輸出11
System.out.println(sum1);//輸出21
}
二、指派運算符
2.1、常見的指派運算符
運算符 | 含義 | 舉例 |
---|---|---|
= | 等于 | c=a+b就是将a+b的值賦給c |
+= | 加等于 | a+=1等價于a=a+1 |
-= | 減等于 | a-=1等價于a=a-1 |
*= | 乘等于 | a*=b等價于a=a*b |
/= | 除等于 | a/=b等價于a=a/b |
%= | 求餘等于 | a%=b等價于a=a%b |
2.2、關于a+=1與a=a+1的差別
雖然在上面說的a+=1是等價于a=a+1,但是他們兩還是有差別的。
@Test
public void c() {
byte a=1;
/*a=a+1;
* 這裡會報編譯錯誤,由于a+1出現類型轉換,變為int類型,是以再指派給byte類型是以編譯錯誤
* */
a+=1;
/*這裡是不會出現編譯錯誤的,這就是它的特殊之處
* */
System.out.println(a);//輸出2
byte b=127;
b+=1;
System.out.println(b);
//輸出-128,是以其實就是b=(byte)(b+1);b+1為128,超出byte類型的範圍,資料溢出為-128
}
原因:+=運算符,是java語言規定的一進制運算符(這裡我将它歸為指派運算符有些不妥),Java有自動轉換機制,java編譯器會對其進行特殊處理,預設的向右轉換類型,不需要人工轉換。
2.3、各種指派運算符的例子
@Test
public void d() {
int a=10;
double b=10;
System.out.println(a+=b);
//輸出20 a=(int)(a+b)=(int)(10+10)=20
System.out.println(b+=a);
//輸出30.0 b=a+b;double類型大,是以不需要自動轉換 b=20+10=30.0
int a1=10;
int b1=10;
System.out.println(a1*=b1);//輸出100
System.out.println(a1/=b1);//輸出10
System.out.println(a1%=b1);//輸出0
System.out.println(a1-=b1);//-10
}
三、關系運算符
3.1 常見關系運算符
關系運算符有時候也稱為比較運算符,運算的結果一定為布爾值
符号 | 含義 | 舉例 |
> | 判斷是否大于 | boolean a=3>2; a=true |
< | 判斷是否小于 | boolean a=3<2; a=false |
>= | 判斷是否大于等于 | boolean a=3<=3; a=true |
<= | 判斷是否小于等于 | boolean a=3>=4; a=fasle |
== | 判斷是否等于 | boolean a=3==4; a=false |
!= | 判斷是否不等于 | boolean a=3!=4; a=true |
注意點:
- < 、>、>=、<=隻能比較數值類型,是以不能比較布爾類型和大多數應用類型,但是有些基本資料類型包裝類型可以。
- ==、!= 既能比較基本資料類型,也能比較引用資料類型。但是在比較引用資料類型的時候比較的就是位址了。
@Test
public void e() {
int a1=10;
int b1=10;
boolean a2=false;
boolean b2=false;
Integer a3=10;
Integer b3=10;
A a4=new A();
A b4=new A();
System.out.println(a1>b1);
/*System.out.println(a2>b2); 非數值類型不能比較大小*/
System.out.println(a3>b3);
/*System.out.println(a4>b4);不能比較大小*/
System.out.println(a1==b1);
System.out.println(a2==b2);//true
System.out.println(a3==b3);
//相等,由于基本資料類型包裝類Integer的自動裝箱的特性,直接從靜态數組中取的,是以不是new的
System.out.println(a4==b4);
//false,由于是new出來的不等
}
3.2、==與equals的差別
首先我們要知道,equals方法是Object類中的一個方法,而Object類是所有類的父類。首先我們先看一下Object類中equals方法的源代碼:
public boolean equals(Object obj) {
return (this == obj);
}
可以看出Object類中該方法的邏輯就是==,是以Object類中給出的equals方法就是判斷是否==;
那我們再看一下String類的equals方法,如下圖:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
可以看出,String類中的equals不再是簡簡單單的直接判斷==;它的equals方法是先判斷它們是否==,如果不等再判斷兩個引用是否為同類或父子類關系,是的話再判斷是否值一樣,一樣則傳回true,否則傳回fasle。是以使用equals方法時要看該引用對應的類的equals方法的實作邏輯,一般情況下是String的話就是先比較位址,位址相等就為true,不為再比較内容,内容一樣也是為true。
是以==與equals的差別可以總結為以下幾點:
- ==是既能比較基本資料類型,比較基本資料類型的時候比較的是值是否相等。又能比較引用資料類型,比較引用資料類型比較的是引用對應的位址是否相等。
- 而equals是一個方法,是以隻能用來比較引用資料類型,要根據類中該方法實作的邏輯是什麼來看比較的是什麼。一般情況下就是String類型和自定義的類。對應String類型是判斷内容是否一緻。
@Test
public void f() {
String a=new String("abc");//new出來的對象放在了堆中
String b=new String("abc");//不管内容中有無,都是直接new出一個新的對象
String c="abc";//放在常量池中
String d="abc";//現在常量池中找師傅有abc,有的話就将d指向該對象
System.out.println(a.equals(b));//true 隻判斷内容是否相等
System.out.println(a==b);//false 判斷位址是的相等
System.out.println(a.equals(c));//true
System.out.println(a==c);//false 位址不同
System.out.println(a==d);//true 位址一樣,由于都指向一個常量池中的同一個對象
}
四、邏輯運算符
4.1、常用邏輯運算符
首先邏輯運算符運算的對象必須還是布爾值,即符号兩邊必須是布爾類型。
運算符 | 名稱 | 舉例 |
&& | 與 | a&&b,a和b都為true,結果才為true,否則為false |
|| | 或 | a||b,a和b都為false,結果才為false,否則為true |
! | 非 | !a,a為false,則結果為true。即結果相反 |
變量a | 變量b | a&&b | a||b | !a |
true | true | true | true | false |
true | false | false | true | false |
false | false | false | false | true |
false | true | false | true | true |
4.2、關于邏輯運算符中"短路"的問題
- 對于&&而言,當第一個操作數為false時,将不會判斷第二個操作數。
- 對于 || 而言,當第一個操作數為true是,将不會判斷第二個操作數。
@Test
public void g() {
int a=10;
int b=10;
boolean c=a>10 && b++>10;
System.out.println(c);
System.out.println(b);//輸出10,由于a>10已經為False之後,後面的b++也就不會執行
boolean d=a<11 || b++>10;
System.out.println(d);
System.out.println(b);//也是輸出10,前面的a<11已經為true,是以後面的b++也不執行
}
五、條件運算符
即為三目運算符,形式為:布爾表達式 ? 表達式1 :表達式2
運算過程:如果布爾表達式的值為 true ,則傳回 表達式1 的值,否則傳回 表達式2 的值
用處:和if else的分支結構作用有點類似。但是寫法比 if else簡潔。
@Test
public void h() {
int[] a= {-1,2,0};
for(int i=0;i<a.length;i++) {
a[i]=a[i]>=0?a[i]:0;//将數組中小于0的數字變為0
}
for(int b:a) {
System.out.println(b);//利用增強for循環輸出數組中的值
}
}
六、位運算符
6.1、常用位運算符
符号 | 含義 |
& | 按位與 |
| | 按位或 |
~ | 非(取反運算符) |
^ | 異或 |
<< | 左移運算符 |
>> | 右移運算符 |
>>> | 無符号右移運算符 |
6.2、按位與 & 詳解
按位與 '&' 與邏輯與 '&&' 不同,邏輯與 '&&' 隻能操作布爾類型的值,而按位與 '&'不僅能操作布爾類型的值,還能操作整數型基本類型。且按位與 '&' 不像邏輯與 '&&'一樣有短路效應。
- 操作布爾類型的值時,與邏輯與 '&&' 類似,也是見false則false,就是沒有短路效應。
- 操作整數基本資料類型是,即将整數化為二進制,然後相同位上計算,相同位都是1則結果為1,否則為0
例如:3&4
3的二進制為 0000 0000 0000 0011
4的二進制為 0000 0000 0000 0100
則結果為 0000 0000 0000 0000 對應的二級制為0,是以3&4=0;
(1)按位與的常見作用:清0,取一個數中的指定位數(例如取int類型值的低八位)
例如int類型變量a對應的二進制為 0010 0001 0000 1010 ,現在求它的低八位,也就是1010,就可以使用a&15
15對應的二進制為 0000 0000 0000 1111 是以 ,a&15的結果就為 0000 0000 0000 1010
(2)判斷一個數的奇偶性:n&1 == 1?”奇數”:”偶數”
(3)面試題:優化n%8
解答:n&7
原因:對8取模(求餘)運算的定義就是整除8後的餘數,而對于8來說,這個餘數恰好就是這個數的二進制表示的低3位; 是以對8取模等價于擷取資料的低3位,這由恰好等價于 &7 的結果。
6.3、按位或 | 詳解
按位或 '|' 與邏輯或 '||' 不同,邏輯與 ' || ' 隻能操作布爾類型的值,而按位與 ' | '不僅能操作布爾類型的值,還能操作整數型基本類型。且按位或 '|' 不像邏輯或 ' || '一樣有短路效應。
- 操作布爾類型的值時,與邏輯或 ' || ' 類似,也是見true則true,就是沒有短路效應。
- 操作整數基本資料類型是,即将整數化為二進制,然後相同位上計算,隻要有一個1就為1,否則結果為0
例如 3 | 4
3的二進制為 0000 0000 0000 0011
4的二進制為 0000 0000 0000 0100
則結果為 0000 0000 0000 0111 對應的二級制為7,是以3&4=7;
按位或的作用:将一個數的某些位置變為1
6.4、按位非 ~詳解
也稱為取反運算符,是一個一進制運算符,是以隻能對一個操作數進行操作。按位非就是将各位數字取反,0變為1,1變為0;
例如 4的二進制為 0000 0000 0000 0100
是以~4的二進制為 1111 1111 1111 1011 轉換為是十進制為-5
常見作用:一個數的相反數=該數取反+1 例如4的相反數-4=~4+1=-5+1=-4
6.5、異或 ^ 詳解
将數轉換為二進制之後運算,然後不相同的結果就為1; 0^0=0 1^0=1 0^1=1 1^1=0
例子:4的二進制為 0000 0000 0000 0100
5的二進制為 0000 0000 0000 0110
4^5的二級制為 0000 0000 0000 0010 轉換為十進制為2
異或^的作用執行個體:不适用臨時變量交換兩個數
我們經常寫變量交換時,是以如下,用了一個臨時變量來交換的;
@Test
public void a() {
int a=3;
int b=4;
int c;//定義的臨時變量
c=a;
a=b;
b=c;
System.out.println(a);//輸出4
System.out.println(b);//輸出3
}
但是利用異或運算符不用使用臨時變量
@Test
public void b() {
int a=3;
int b=4;
a=a^b;
b=b^a;//b=b^(a^b) ->b=a
a=a^b;//a=(a^b)^(b^a) ->a=b
System.out.println(a);//輸出4
System.out.println(b);//輸出3
}
6.6、左移、右移、無符号右移動
- 左移運算符 << :符号位不變,低位補0;
- 右移運算符 >> :是低位溢出,符号位不變,并用符号位補溢出高位
- 無符号右移運算符>>>:低位溢出,高位補0,注意,無符号右移(>>>)中的符号位(最高位)也跟着變,無符号的意思是将符号位當作數字位看待。
@Test
public void c() {
int a=4;
System.out.println(a<<2);
/* 0000 0000 0000 0100 a的二進制
* 000000 0000 0001 0000 低位補兩個0
* 0000 0000 0001 0000 高位溢出,是以a<<2=8
* */
System.out.println(a>>2);
/* 0000 0000 0000 0100
* 0000 0000 0000 000100 符号位補高位
* 0000 0000 0000 0001 低位溢出 是以 a>>2=1
* */
int b=-1;
System.out.println(b>>>1);
/* 1111 1111 1111 1111
* 0111 1111 1111 11111 右移一位,高位補0,
* 0111 1111 1111 1111 低位溢出 結果為 2147483647
* */
}
七、各種運算符的優先級
下圖為java中各種運算符的優先級,可以記一下,但有時候不太清楚的時候就直接用括号()吧!
運算符 | 結合性 |
[ ] . ( ) (方法調用) | 從左向右 |
! ~ ++ -- +(一進制運算) -(一進制運算) | 從右向左 |
* / % | 從左向右 |
+ - | 從左向右 |
<< >> >>> | 從左向右 |
< <= > >= instanceof | 從左向右 |
== != | 從左向右 |
& | 從左向右 |
^ | 從左向右 |
| | 從左向右 |
&& | 從左向右 |
|| | 從左向右 |
?: | 從右向左 |
= | 從右向左 |