1 java運(yùn)算符
1.1 各個(gè)運(yùn)算符一覽
| 序號(hào) | 符號(hào) | 名稱 | 結(jié)合性(與操作數(shù)) | 對(duì)目 | 說明 |
|---|---|---|---|---|---|
| 1 | . | 點(diǎn) | 從左到右 | 雙目 | |
| 2 | () | 圓括號(hào) | 從左到右 | ||
| 3 | [ ] | 方括號(hào) | 從左到右 | ||
| 4 | + | 正號(hào) | 從右到左 | 單目 | |
| 5 | - | 負(fù)號(hào) | 從右到左 | 單目 | |
| 6 | ++ | 自增 | 從右到左 | 單目 | 前綴增,后綴增 |
| 7 | -- | 自減 | 從右到左 | 單目 | 前綴減,后綴減 |
| 8 | ~ | 按位非/取補(bǔ)運(yùn)算 | 從右到左 | 單目 | |
| 9 | ! | 邏輯非 | 從右到左 | 單目 | “!”不可以與“=”聯(lián)用 |
| 10 | * | 乘 | 從左到右 | 雙目 | |
| 11 | / | 除 | 從左到右 | 雙目 | 整數(shù)除法: 取商的整數(shù)部分,小數(shù)部分去掉,不四舍五入 |
| 12 | % | 取余 | 從左到右 | 雙目 | |
| 13 | + | 加 | 從左到右 | 雙目 | |
| 14 | - | 減 | 從左到右 | 雙目 | |
| 15 | << | 左移位運(yùn)算符 | 從左到右 | 雙目 | |
| 16 | >> | 右移位運(yùn)算符 | 從左到右 | 雙目 | |
| 17 | >>> | 無符號(hào)右移位運(yùn)算符 | 從左到右 | 雙目 | |
| 18 | < | 小于 | 從左到右 | 雙目 | |
| 19 | <= | 小于或等于 | 從左到右 | 雙目 | |
| 20 | > | 大于 | 從左到右 | 雙目 | |
| 21 | >= | 大于或等于 | 從左到右 | 雙目 | |
| 22 | instanceof | 確定某對(duì)象是否屬于指定的類 | 從左到右 | 雙目 | |
| 23 | == | 等于 | 從左到右 | 雙目 | |
| 24 | != | 不等于 | 從左到右 | 雙目 | |
| 25 | & | 按位與 | 從左到右 | 雙目 | |
| 26 | | | 按位或 | 從左到右 | 雙目 | |
| 27 | ^ | 按位異或 | 從左到右 | 雙目 | |
| 28 | && | 短路與 | 從左到右 | 雙目 | |
| 29 | || | 短路或 | 從左到右 | 雙目 | |
| 30 | ?: | 條件運(yùn)算符 | 從右到左 | 三目 | |
| 31 | = | 賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 32 | += | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 33 | -= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 34 | *= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 35 | /= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 36 | %= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 37 | |= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 38 | ^= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 39 | <<= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 40 | >>= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 | |
| 41 | >>>= | 混合賦值運(yùn)算符 | 從右到左 | 雙目 |
1.2 部分運(yùn)算符說明
部分運(yùn)算符說明:
算數(shù)運(yùn)算符:+ :加法,- :減法,* :乘法,/ :除法,% :取余運(yùn)算
關(guān)系運(yùn)算符:
-
<:只能比較基本類型數(shù)據(jù)之間的關(guān)系,不能比較對(duì)象之間的關(guān)系; -
>: (同關(guān)系運(yùn)算符<); -
<=: (同關(guān)系運(yùn)算符<); -
>=: (同關(guān)系運(yùn)算符<); -
==:若使用該運(yùn)算符比較兩個(gè)對(duì)象的引用(變量),則實(shí)質(zhì)上是比較兩個(gè)變量是否引用了相同的對(duì)象。所謂相同的對(duì)象是指,是否是在堆棧(Heap)中開辟的同一塊兒內(nèi)存單元中存放的對(duì)象。
若比較兩個(gè)對(duì)象的引用(變量)所引用的對(duì)象的內(nèi)容是否相同,則應(yīng)該使用equals()方法,該方法的返回值類型是布爾值。需要注意的是:若用類庫中的類創(chuàng)建對(duì)象,則對(duì)象的引用調(diào)用equals()方法比較的是對(duì)象的內(nèi)容;若用自定義的類來創(chuàng)建對(duì)象,則對(duì)象的引用調(diào)用equals()方法比較的是兩個(gè)引用是否引用了同一個(gè)對(duì)象,因?yàn)榈诙N情況equals()方法默認(rèn)的是比較引用。 -
!=:(同關(guān)系運(yùn)算符==)
邏輯運(yùn)算符 (操作符只能是布爾類型的)&&,||,!
public class Demo {
public static void main(String[] args) {
// System.out.println((!'1'||'1')+5);//編譯錯(cuò)誤
// System.out.println(!5);//編譯錯(cuò)誤
// System.out.println(('1'||'1')+5);//編譯錯(cuò)誤
// System.out.println(1||2);//編譯錯(cuò)誤
// System.out.println(5-3||4-2);//編譯錯(cuò)誤 8
System.out.println(5<3||4>3);//true 9 }
}
位運(yùn)算符:&,|,^,!:不可以與=聯(lián)用,因?yàn)?code>!是一元操作符;不可以對(duì)布爾類型的數(shù)據(jù)進(jìn)行按位非運(yùn)算
移位運(yùn)算符(只能處理整數(shù)運(yùn)算符):Char、byte、short類型,在進(jìn)行移位之前,都將被轉(zhuǎn)換成int類型,移位后的結(jié)果也是int類型;移位符號(hào)右邊的操作數(shù)只截取其二進(jìn)制的后5位(目的是防止因?yàn)橐莆徊僮鞫?code>int類型的表示范圍:2的5次方是32,int類型的最大范圍是32位);對(duì)long類型進(jìn)行移位,結(jié)果仍然是long類型,移位符號(hào)右邊的操作符只截取其二進(jìn)制的后6位。
>> :若符號(hào)位為正,則在最高位插入0;若符號(hào)位為負(fù),則在最高位插入1
>>>:無論正負(fù),都在最高位插入0
1.3 java基本位操作
1.3.1 位操作符號(hào)
基本位操作符號(hào):
-
~按位非(NOT)
公式:~n=-n-1 -
&按位與(AND) -
|按位或(OR) -
^按位異或(XOR) -
>>右移 -
>>>無符號(hào)右移 -
<<左移
前面幾個(gè)都非常簡(jiǎn)單,主要是移位操作比較容易出錯(cuò).
首先要搞清楚參與運(yùn)算的數(shù)的位數(shù),如int的是32位,long的是64位。
如int i = 1; i的二進(jìn)制原碼表示為: 00000000000000000000000000000001
long l = 1;l的二進(jìn)制原碼表示為: 0000000000000000000000000000000000000000000000000000000000000001
1.3.2 原碼反碼補(bǔ)碼
1.3.2.1 相關(guān)定義
各個(gè)相關(guān)概念定義如下:
機(jī)器數(shù):一個(gè)數(shù)在計(jì)算機(jī)中的二進(jìn)制表示形式, 叫做這個(gè)數(shù)的機(jī)器數(shù)。機(jī)器數(shù)是帶符號(hào)的,在計(jì)算機(jī)用一個(gè)數(shù)的最高位存放符號(hào),正數(shù)為0, 負(fù)數(shù)為1
比如,十進(jìn)制中的數(shù)+3,計(jì)算機(jī)字長(zhǎng)為8位,轉(zhuǎn)換成二進(jìn)制就是00000011。如果是-3,就是10000011。那么,這里的00000011和10000011就是機(jī)器數(shù)。真值:因?yàn)榈谝晃皇欠?hào)位,所以機(jī)器數(shù)的形式值就不等于真正的數(shù)值。例如上面的有符號(hào)數(shù)10000011,其最高位1代表負(fù),其真正數(shù)值是-3而不是形式值131(10000011轉(zhuǎn)換成十進(jìn)制等于131)。所以,為區(qū)別起見,將帶符號(hào)位的機(jī)器數(shù)對(duì)應(yīng)的真正數(shù)值稱為機(jī)器數(shù)真值。
例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1原碼:原碼就是符號(hào)位加上真值的絕對(duì)值, 即用第一位表示符號(hào), 其余位表示值.
比如:如果是8位二進(jìn)制:[+1]原 = 0000 0001,[-1]原 = 1000 0001
第一位是符號(hào)位. 因?yàn)榈谝晃皇欠?hào)位, 所以8位二進(jìn)制數(shù)的取值范圍就是:[1111 1111 , 0111 1111],即:[-127 , 127]
原碼是人腦最容易理解和計(jì)算的表示方式.反碼:反碼的表示方法是:正數(shù)的反碼跟原碼一樣,負(fù)數(shù)的反碼是在其原碼的基礎(chǔ)上,符號(hào)位不變,其余各位取反
比如:[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
可見如果一個(gè)反碼表示的是負(fù)數(shù), 人腦無法直觀的看出來它的數(shù)值. 通常要將其轉(zhuǎn)換成原碼再計(jì)算補(bǔ)碼:補(bǔ)碼的表示方法是:正數(shù)的補(bǔ)碼就是其本身;負(fù)數(shù)的補(bǔ)碼是在其原碼的基礎(chǔ)上, 符號(hào)位不變, 其余各位取反, 最后+1. (即在反碼的基礎(chǔ)上+1)
比如:[+1] = [00000001]原 = [00000001]反 = [00000001]補(bǔ)
[-1] = [10000001]原 = [11111110]反 = [11111111]補(bǔ)
對(duì)于負(fù)數(shù), 補(bǔ)碼表示方式也是人腦無法直觀看出其數(shù)值的. 通常也需要轉(zhuǎn)換成原碼在計(jì)算其數(shù)值
如果有運(yùn)算得話,負(fù)數(shù)都是用補(bǔ)碼參與運(yùn)算的,得到的結(jié)果也是補(bǔ)碼,需要減1取反獲得原碼
1.3.2.2 為何要使用原碼, 反碼和補(bǔ)碼
在開始深入學(xué)習(xí)前, 先死記硬背上面的原碼, 反碼和補(bǔ)碼的表示方式以及計(jì)算方法.
現(xiàn)在我們知道了計(jì)算機(jī)可以有三種編碼方式表示一個(gè)數(shù). 對(duì)于正數(shù)因?yàn)槿N編碼方式的結(jié)果都相同:
[+1] = [00000001]原 = [00000001]反 = [00000001]補(bǔ)
所以不需要過多解釋. 但是對(duì)于負(fù)數(shù):
[-1] = [10000001]原 = [11111110]反 = [11111111]補(bǔ)
可見原碼, 反碼和補(bǔ)碼是完全不同的. 既然原碼才是被人腦直接識(shí)別并用于計(jì)算表示方式, 為何還會(huì)有反碼和補(bǔ)碼呢?
首先, 因?yàn)槿四X可以知道第一位是符號(hào)位, 在計(jì)算的時(shí)候我們會(huì)根據(jù)符號(hào)位, 選擇對(duì)真值區(qū)域的加減. 但是對(duì)于計(jì)算機(jī), 加減乘數(shù)已經(jīng)是最基礎(chǔ)的運(yùn)算, 要設(shè)計(jì)的盡量簡(jiǎn)單. 計(jì)算機(jī)辨別符號(hào)位顯然會(huì)讓計(jì)算機(jī)的基礎(chǔ)電路設(shè)計(jì)變得十分復(fù)雜! 于是人們想出了將符號(hào)位參與運(yùn)算的方法. 我們知道, 根據(jù)運(yùn)算法則減去一個(gè)正數(shù)等于加上一個(gè)負(fù)數(shù), 即: 1-1 = 1 + (-1) = 0, 所以機(jī)器可以只有加法而沒有減法, 這樣計(jì)算機(jī)運(yùn)算的設(shè)計(jì)就更簡(jiǎn)單了.
于是人們開始探索 將符號(hào)位參與運(yùn)算, 并且只保留加法的方法. 首先來看原碼。計(jì)算十進(jìn)制的表達(dá)式:
1-1=0
1 - 1 = 1 + (-1)
= [00000001]原 + [10000001]原
= [10000010]原 = -2
如果用原碼表示, 讓符號(hào)位也參與計(jì)算, 顯然對(duì)于減法來說, 結(jié)果是不正確的.這也就是為何計(jì)算機(jī)內(nèi)部不使用原碼表示一個(gè)數(shù).
為了解決原碼做減法的問題, 出現(xiàn)了反碼。計(jì)算十進(jìn)制的表達(dá)式:
1-1=0
1 - 1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反 = [1000 0000]原
= -0
發(fā)現(xiàn)用反碼計(jì)算減法, 結(jié)果的真值部分是正確的. 而唯一的問題其實(shí)就出現(xiàn)在0這個(gè)特殊的數(shù)值上. 雖然人們理解上+0和-0是一樣的, 但是0帶符號(hào)是沒有任何意義的. 而且會(huì)有[0000 0000]原和[1000 0000]原兩個(gè)編碼表示0.
于是補(bǔ)碼的出現(xiàn), 解決了0的符號(hào)以及兩個(gè)編碼的問題:
1-1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]補(bǔ) + [1111 1111]補(bǔ)
= [0000 0000]補(bǔ)=[0000 0000]原
這樣0用[0000 0000]表示, 而以前出現(xiàn)問題的-0則不存在了.而且可以用[1000 0000]表示-128:
(-1) + (-127) = [1000 0001]原 + [1111 1111]原
= [1111 1111]補(bǔ) + [1000 0001]補(bǔ)
= [1000 0000]補(bǔ)
-1-127的結(jié)果應(yīng)該是-128, 在用補(bǔ)碼運(yùn)算的結(jié)果中, [1000 0000]補(bǔ) 就是-128. 但是注意因?yàn)閷?shí)際上是使用以前的-0的補(bǔ)碼來表示-128, 所以-128沒有原碼和反碼表示.(對(duì)-128的補(bǔ)碼表示[1000 0000]補(bǔ)算出來的原碼是[0000 0000]原, 這是不正確的)
使用補(bǔ)碼, 不僅僅修復(fù)了0的符號(hào)以及存在兩個(gè)編碼的問題, 而且還能夠多表示一個(gè)最低數(shù). 這就是為什么8位二進(jìn)制, 使用原碼或反碼表示的范圍為[-127, +127], 而使用補(bǔ)碼表示的范圍為[-128, 127].
因?yàn)闄C(jī)器使用補(bǔ)碼, 所以對(duì)于編程中常用到的32位int類型, 可以表示范圍是: [,
] 因?yàn)榈谝晃槐硎镜氖欠?hào)位.而使用補(bǔ)碼表示時(shí)又可以多保存一個(gè)最小值.
1.3.2.3 負(fù)數(shù)運(yùn)算
負(fù)數(shù)參與的運(yùn)算,得到的是 補(bǔ)碼,需要將補(bǔ)碼先減1,然后逐位取反,得到原碼,即為運(yùn)算結(jié)果。
0例外,如果得到的是0,則不需減1和取反。
另外,兩個(gè)正數(shù)運(yùn)算后得到的就是原碼,不需減1和取反。
舉例:
1^-1,
-1 :
10000000000000000000000000000001--原碼
11111111111111111111111111111110--反碼
11111111111111111111111111111111--補(bǔ)碼
1
00000000000000000000000000000001`--原碼
則1^-1等于
11111111111111111111111111111111^
00000000000000000000000000000001=
11111111111111111111111111111110--補(bǔ)碼
11111111111111111111111111111101--反碼
10000000000000000000000000000010--原碼==-2
即1^-1=-2
舉例:
1^-2
-2
10000000000000000000000000000010--原碼
01111111111111111111111111111101--反碼
01111111111111111111111111111110--補(bǔ)碼
1
00000000000000000000000000000001--原碼
則1^-2等于
01111111111111111111111111111110^
00000000000000000000000000000001=
01111111111111111111111111111111--補(bǔ)碼
01111111111111111111111111111110--反碼
10000000000000000000000000000001--原碼==-1
1.3.2.4 轉(zhuǎn)換16進(jìn)制為什么需要 &0xff
例如:把漢字轉(zhuǎn)為16進(jìn)制需要如下:
@Test
public void testEnHex() throws UnsupportedEncodingException {
String s = "嚴(yán)";
byte[] bytes = s.getBytes("utf-8");
StringBuffer sb = new StringBuffer();
for (int i = 0;i<bytes.length;i++){
String s1 = Integer.toHexString(bytes[i] & 0x0ff).toUpperCase();
if(s1.length()<2){
sb.append(0);
}
sb.append(s1);
}
System.out.println(sb.toString());
}
如上的為什么需要 &0x0ff呢
先看下添加和去掉結(jié)果:
有&0x0ff是E4B8A5,沒有時(shí)是FFFFFFE4FFFFFFB8FFFFFFA5
沒有&0x0ff轉(zhuǎn)換后多了一串FF
這是因?yàn)?code>Integer.toHexString()的接收參數(shù)是int,不是byte,于是運(yùn)算是會(huì)先把byte強(qiáng)制轉(zhuǎn)換為int
由于java中強(qiáng)制轉(zhuǎn)換是保持值不變,而在計(jì)算機(jī)中數(shù)都是用 補(bǔ)碼 表示的,java中int是32位4個(gè)byte, 正數(shù)補(bǔ)碼是正數(shù)本身,這樣不會(huì)有問題,強(qiáng)轉(zhuǎn)為32位時(shí)前面24位會(huì)填充0,
而負(fù)數(shù)的補(bǔ)碼是將其對(duì)應(yīng)正數(shù)二進(jìn)制表示所有位取反(原碼符號(hào)位除外,0變1,1變0)后加1,于是32位的0x00 00 00 80(0000 ... 0000 1000 0000)補(bǔ)碼是0xFF FF FF 80(1111 ... 1111 1000 0000),前面是填充的1
所以Integer.toHexString()后就會(huì)變成前面多了一串F
所以要得到正確的結(jié)果,需要用 Integer.toHexString(card[i] & 0xff),這樣會(huì)只取最后8位(1byte=8位二進(jìn)制),前面都置0,這樣轉(zhuǎn)換出來就是正確的了
為什么非要添加&0x0ff,不加也有結(jié)果,只是長(zhǎng)點(diǎn)而已嘛
如果不加&0x0ff,那么保存的字符長(zhǎng)度難以統(tǒng)一 ,字符串長(zhǎng)度太長(zhǎng)。
并且byte的取值范圍在[-128,127]之間,16進(jìn)制表示用兩個(gè)符號(hào)就夠了0x00—0xff。負(fù)數(shù)如果用這么多字符,造成正負(fù)數(shù)符號(hào)長(zhǎng)度不統(tǒng)一怎么保存呢?從16進(jìn)制還原成2進(jìn)制時(shí)怎么按長(zhǎng)度區(qū)分各個(gè)數(shù)字呢?
所以我們把byte與運(yùn)算&0xff。以-1為例:1111 1111 1111 1111 1111 1111 1111 1111 & 0xff 得到0000 0000 0000 0000 0000 0000 1111 1111即0xff。這個(gè)數(shù)結(jié)果依然是-1。用這種方式處理后,byte不論正負(fù),得到的都是二位的16進(jìn)制數(shù)。以兩位存儲(chǔ),兩位還原,很方便
還原代碼如下,使用E4B8A5(用&0xff)能得到正確值,但是使用FFFFFFE4FFFFFFB8FFFFFFA5(沒有用&0xff)就不能得到正確的值
public void testHanzi() {
String hexStr = "E4B8A5";
String str = "0123456789ABCDEF" ;
char [] hexs = hexStr.toCharArray();
byte [] bytes = new byte [hexStr.length() / 2 ];
int n;
for ( int i = 0 ; i < bytes.length; i++) {
n = str.indexOf(hexs[ 2 * i]) * 16 ;
n += str.indexOf(hexs[ 2 * i + 1 ]);
bytes[i] = ( byte ) (n & 0xff );
}
System.out.println(new String(bytes));
}
按照16進(jìn)制兩位兩位判斷,在進(jìn)行byte強(qiáng)轉(zhuǎn)時(shí)高于127時(shí),溢出轉(zhuǎn)為負(fù)值
1.3.3 常用的位運(yùn)算符運(yùn)算
常用的位運(yùn)算符--0在位運(yùn)算中是比較特殊的
^ 異或:相同為0,相異為1; 任何數(shù)與0異或都等于原值。
& 與: 全1為1, 有0為0;任何數(shù)與0異或都等于0。
| 或: 有1為1, 全0為0。任何數(shù)與0或都等于原值。
<<左移: 補(bǔ)0。
>> 右移:符號(hào)位是0補(bǔ)0,是1補(bǔ)1。
>>>無符號(hào)右移:補(bǔ)0。
~ 非:逐位取反
1.3.3.1 左右位移
<<:邏輯左移,右邊補(bǔ)0,符號(hào)位和其他位一樣.
正數(shù): x<<1一般相當(dāng)于2x,但是可能溢出.
溢出范圍: ~ (
-1) 二進(jìn)制表示 010000...000到01111....1111,移位后最高為變?yōu)?了,變成負(fù)數(shù)了.
負(fù)數(shù):
1111111111111111111111111111111 this is 2^31
1000000000000000000000000000000 this is 2^30
x<<1一般也相當(dāng)于2x,也有可能溢出.所以, x*32可以寫成x<<5
溢出范圍: ~-(
+1)二進(jìn)制表示
10000...000到101111...1111,移位后最高為變成0了,變成正數(shù)了.
>> :算術(shù)右移,和上面的不對(duì)應(yīng),為正數(shù)時(shí)左邊補(bǔ)0,為負(fù)數(shù)時(shí)左邊補(bǔ)1.
x>>1,相當(dāng)于x/2,余數(shù)被舍棄,因?yàn)檫@個(gè)是縮小,所以不會(huì)溢出.
不過有一點(diǎn)要注意: -1右移多少位都是-1.
另外舍棄的余數(shù)是正的, 3>>1=1 舍棄的余數(shù)是1.
-3>>1=-2 舍棄的余數(shù)也是1,而不是-1.
對(duì)于正數(shù) x>>1和x/2相等
對(duì)于負(fù)數(shù)x>>1和x/2不一定相等.
>>> :邏輯右移,這個(gè)才是和<<對(duì)應(yīng)的
這個(gè)把符號(hào)位一起移動(dòng),左邊補(bǔ)0
對(duì)于正數(shù),>>>和>>是一樣的
對(duì)于負(fù)數(shù),右移之后就變成正數(shù)了.
可以使用Integer.toBinaryString(int i)來看01比特,更加直觀.
考慮下面的代碼:
for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }
用移位操作替代乘法操作可以極大地提高性能。下面是修改后的代碼:
for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }
修改后的代碼不再做乘以8的操作,而是改用等價(jià)的左移3位操作,每左移1位相于乘以2。相應(yīng)地,右移1位操作相當(dāng)于除以2。值得一提的是,雖然移位操作速度快,但可能使代碼比較難于理解,所以最好加上一些注釋。
無符號(hào)右移位操作符>>>在將bit串右移位時(shí),從bit串的最左邊填充0,這和帶符號(hào)右移位操作符>>不同。>>在將bit串右移位時(shí),從bit串的最左邊填充原來最左邊的位。也就是說,bit串原來最左邊的位是符號(hào)位,如果為1,則在帶符號(hào)右移時(shí)最左邊始終填充1;如果為0,則在帶符號(hào)右移時(shí)最左邊始終填充0。
移位操作符的例子見下表。
| 操作 | 結(jié)果 | 說明 |
|---|---|---|
| 00110010<< 2 | 11001000 | 右邊始終填充0 |
| 00110010 >> 2 | 00001100 | 結(jié)果和>>>一樣 |
| 00110010 >>> 2 | 00001100 | 結(jié)果和>>一樣 |
| 10110010 >> 2 | 11101100 | 結(jié)果和>>>不一樣 |
| 10110010 >>> 2 | 100101100 | 結(jié)果和>>不一樣 |
按位與操作符&對(duì)兩個(gè)bit串按位進(jìn)行邏輯與,按位或操作符|對(duì)兩個(gè)bit串按位進(jìn)行邏輯或,按位異或操作符^對(duì)兩個(gè)bit串按位進(jìn)行異或操作。運(yùn)算規(guī)則如下表所示。
| 按位與 | 按位或 | 按位異或 |
|---|---|---|
| 0 & 0 = 0 | 0 | 0 = 0 | 0 ^ 0 = 0 |
| 0 & 1 = 0 | 0 | 1 = 1 | 0 ^ 1 = 1 |
| 1 & 0 = 0 | 1 | 0 = 1 | 1 ^ 0 = 1 |
| 1 & 1 = 1 | 1 | 1 = 1 | 1 ^ 1 = 0 |
2 基本數(shù)據(jù)類型
基本類型,或者叫做內(nèi)置類型,是JAVA中不同于類的特殊類型。它們是我們編程中使用最頻繁的類型
基本類型共有八種,它們分別都有相對(duì)應(yīng)的包裝類。關(guān)于它們的詳細(xì)信息請(qǐng)如下:
基本類型可以分為三類,字符類型char,布爾類型boolean以及數(shù)值類型byte、short、int、long、float、double。
數(shù)值類型又可以分為整數(shù)類型byte、short、int、long和浮點(diǎn)數(shù)類型float、double。JAVA中的數(shù)值類型不存在無符號(hào)的,它們的取值范圍是固定的,不會(huì)隨著機(jī)器硬件環(huán)境或者操作系統(tǒng)的改變而改變。實(shí)際上,JAVA中還存在另外一種基本類型void,它也有對(duì)應(yīng)的包裝類java.lang.Void,不過我們無法直接對(duì)它們進(jìn)行操作。對(duì)于數(shù)值類型的基本類型的取值范圍,我們無需強(qiáng)制去記憶,因?yàn)樗鼈兊闹刀家呀?jīng)以常量的形式定義在對(duì)應(yīng)的包裝類中了。請(qǐng)看下面的例子:
public class PrimitiveTypeTest {
public static void main(String[] args) {
// byte
System.out.println("基本類型:byte 二進(jìn)制位數(shù):" + Byte.SIZE);
System.out.println("包裝類:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println();
// short
System.out.println("基本類型:short 二進(jìn)制位數(shù):" + Short.SIZE);
System.out.println("包裝類:java.lang.Short");
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
System.out.println();
// int
System.out.println("基本類型:int 二進(jìn)制位數(shù):" + Integer.SIZE);
System.out.println("包裝類:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println();
// long
System.out.println("基本類型:long 二進(jìn)制位數(shù):" + Long.SIZE);
System.out.println("包裝類:java.lang.Long");
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
System.out.println();
// float
System.out.println("基本類型:float 二進(jìn)制位數(shù):" + Float.SIZE);
System.out.println("包裝類:java.lang.Float");
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
System.out.println();
// double
System.out.println("基本類型:double 二進(jìn)制位數(shù):" + Double.SIZE);
System.out.println("包裝類:java.lang.Double");
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
System.out.println();
// char
System.out.println("基本類型:char 二進(jìn)制位數(shù):" + Character.SIZE);
System.out.println("包裝類:java.lang.Character");
// 以數(shù)值形式而不是字符形式將Character.MIN_VALUE輸出到控制臺(tái)
System.out.println("最小值:Character.MIN_VALUE="
+ (int) Character.MIN_VALUE);
// 以數(shù)值形式而不是字符形式將Character.MAX_VALUE輸出到控制臺(tái)
System.out.println("最大值:Character.MAX_VALUE="
+ (int) Character.MAX_VALUE);
}
}
運(yùn)行結(jié)果:
基本類型:byte 二進(jìn)制位數(shù):8
包裝類:java.lang.Byte
最小值:Byte.MIN_VALUE=-128
最大值:Byte.MAX_VALUE=127
基本類型:short 二進(jìn)制位數(shù):16
包裝類:java.lang.Short
最小值:Short.MIN_VALUE=-32768
最大值:Short.MAX_VALUE=32767
基本類型:int 二進(jìn)制位數(shù):32
包裝類:java.lang.Integer
最小值:Integer.MIN_VALUE=-2147483648
最大值:Integer.MAX_VALUE=2147483647
基本類型:long 二進(jìn)制位數(shù):64
包裝類:java.lang.Long
最小值:Long.MIN_VALUE=-9223372036854775808
最大值:Long.MAX_VALUE=9223372036854775807
基本類型:float 二進(jìn)制位數(shù):32
包裝類:java.lang.Float
最小值:Float.MIN_VALUE=1.4E-45
最大值:Float.MAX_VALUE=3.4028235E38
基本類型:double 二進(jìn)制位數(shù):64
包裝類:java.lang.Double
最小值:Double.MIN_VALUE=4.9E-324
最大值:Double.MAX_VALUE=1.7976931348623157E308
基本類型:char 二進(jìn)制位數(shù):16
包裝類:java.lang.Character
最小值:Character.MIN_VALUE=0
最大值:Character.MAX_VALUE=65535
Float和Double的最小值和最大值都是以科學(xué)記數(shù)法的形式輸出的,結(jié)尾的E+數(shù)字表示E之前的數(shù)字要乘以10的多少倍。比如3.14E3就是3.14×1000=3140,3.14E-3就是3.14/1000=0.00314
大家將運(yùn)行結(jié)果與上表信息仔細(xì)比較就會(huì)發(fā)現(xiàn)float、double兩種類型的最小值與Float.MIN_VALUE、 Double.MIN_VALUE的值并不相同,這是為什么呢?實(shí)際上Float.MIN_VALUE和Double.MIN_VALUE分別指的是float和double類型所能表示的最小正數(shù)。也就是說存在這樣一種情況,0到±Float.MIN_VALUE之間的值float類型無法表示,0 到±Double.MIN_VALUE之間的值double類型無法表示。這并沒有什么好奇怪的,因?yàn)檫@些范圍內(nèi)的數(shù)值超出了它們的精度范圍。
需要注意:基本類型存儲(chǔ)在棧中,因此它們的存取速度要快于存儲(chǔ)在堆中的對(duì)應(yīng)包裝類的實(shí)例對(duì)象。從Java5.0(1.5)開始,JAVA虛擬機(jī)(Java Virtual Machine)可以完成基本類型和它們對(duì)應(yīng)包裝類之間的自動(dòng)轉(zhuǎn)換。因此我們?cè)谫x值、參數(shù)傳遞以及數(shù)學(xué)運(yùn)算的時(shí)候像使用基本類型一樣使用它們的包裝類,但這并不意味著你可以通過基本類型調(diào)用它們的包裝類才具有的方法。另外,所有基本類型(包括void)的包裝類都使用了final修飾,因此我們無法繼承它們擴(kuò)展新的類,也無法重寫它們的任何方法。
附:Java中二進(jìn)制,八進(jìn)制,十六進(jìn)制,十進(jìn)制間進(jìn)行相互轉(zhuǎn)