java中運算符詳解


前言

運算符用於執行程序代碼運算,會針對一個以上操作數項目來進行運算。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仔細看一下即可。不過在這里大致說一下其中幾個重要的點。

  1. 運算時,運算結果會向數據類型大的轉換;
  2. 在運算時,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

注意點:

  1. < 、>、>=、<=只能比較數值類型,所以不能比較布爾類型和大多數應用類型,但是有些基本數據類型包裝類型可以。
  2. ==、!= 既能比較基本數據類型,也能比較引用數據類型。但是在比較引用數據類型的時候比較的就是地址了。
@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的區別可以總結為以下幾點:

  1. ==是既能比較基本數據類型,比較基本數據類型的時候比較的是值是否相等。又能比較引用數據類型,比較引用數據類型比較的是引用對應的地址是否相等。
  2. 而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、關於邏輯運算符中"短路"的問題

  1. 對於&&而言,當第一個操作數為false時,將不會判斷第二個操作數。
  2. 對於 || 而言,當第一個操作數為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、左移、右移、無符號右移動

  1. 左移運算符 << :符號位不變,低位補0;
  2. 右移運算符 >> :是低位溢出,符號位不變,並用符號位補溢出高位
  3. 無符號右移運算符>>>:低位溢出,高位補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 從左向右
== != 從左向右
& 從左向右
^ 從左向右
| 從左向右
&& 從左向右
|| 從左向右
?: 從右向左

=

從右向左

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM