1. 基本數(shù)據(jù)類型
Java使用了八種基本數(shù)據(jù)類型获三,這八種基本數(shù)據(jù)類型可以滿足大多數(shù)使用數(shù)據(jù)的情況弄唧。根據(jù)占用不同的內(nèi)存長度袜瞬,八種數(shù)據(jù)類型可以分為五組冲杀,如下表效床。
占用字節(jié)長度 | 不確定 | 1個字節(jié) | 2個字節(jié) | 4個字節(jié) | 8個字節(jié) |
---|---|---|---|---|---|
基本數(shù)據(jù)類型 | boolean | byte | short char |
int float |
long double |
在對這八個基本數(shù)據(jù)類型進(jìn)行介紹的時候?qū)⑹褂孟聢D的結(jié)構(gòu)。
- 類型存儲和計算方式嘗試從硬件系統(tǒng)結(jié)構(gòu)的角度解釋某個基本數(shù)據(jù)類型权谁,包括占用內(nèi)存的大小形式以及常見計算的執(zhí)行過程剩檀。
- 聲明和定義提供了使用該數(shù)據(jù)類型的方法,包括聲明旺芽、定義沪猴、初始化賦值、默認(rèn)值采章。
- 賦值本身有多種方式运嗜,也包括多個注意事項,例如進(jìn)制安排悯舟,不同類型之間的轉(zhuǎn)化担租,以及賦值時的可讀性。
- 運算操作指代了基本數(shù)據(jù)類型作為參數(shù)可以參與哪些運算抵怎,與計算方式不同在于這一部分只介紹運算的輸入輸出奋救,將不再介紹中間過程。
這么安排的原因如下:
- 計算機系統(tǒng)是分層次的反惕,處在第n層的人尝艘,通常要了解第n-1層提供的服務(wù);而類型存儲和計算方式這一部分作為第n-1層的內(nèi)容姿染,有利于深刻了解第n層的輸入和輸出原理背亥。同時有利于回答基本數(shù)據(jù)類型“是什么”。
- 除此之外盔粹,使用聲明定義賦值運算具體闡述“怎么做”隘梨,介紹數(shù)據(jù)類型如何被利用,以及在利用的過程當(dāng)中有什么技巧舷嗡。
在基本數(shù)據(jù)類型之上轴猎,有很多針對基本數(shù)據(jù)類型封裝的類數(shù)據(jù)類型,本文不設(shè)計這部分內(nèi)容进萄。
2. boolean
boolean又稱布爾類型捻脖,只有兩種表現(xiàn)形式锐峭。
2.1 類型存儲和計算方式
boolean代表了true/false,但在Java中并沒有限制實現(xiàn)手段可婶,根據(jù)不同的jvm實現(xiàn)可能會有不同內(nèi)存占用沿癞。在使用boolean數(shù)組的時候會有區(qū)別。
boolean的計算方法與存儲方式有緊密的關(guān)系矛渴。假設(shè)以一個bit作為一個boolean椎扬,那么計算方法就包括獲取bit、存儲bit具温、運算bit蚕涤、并得到結(jié)果bit。
2.2 聲明和定義
聲明方法如下:
boolean a = true;
- 在Java中铣猩,boolean只可以通過true/false進(jìn)行賦值揖铜,否則就會報錯。因為沒有限制實現(xiàn)手段达皿,所有就無法使用一個bit或是一個byte決定值天吓。
例如:這種情況會報錯,無法將byte轉(zhuǎn)為boolean
byte aByte = 0b1;
boolean aBoolean = (boolean) aByte;
- 如果不進(jìn)行顯式得賦值峦椰,boolean變量默認(rèn)為false(某個方法內(nèi)部的本地變量不會賦默認(rèn)值)龄寞。
- 變量命名的時候命名為XXX而非isXXX,因為boolean變量在pojo中的getter就是以isXXX形式存在的们何。
2.3 賦值
賦值包括進(jìn)制萄焦,類型與類型之間的轉(zhuǎn)化,以及內(nèi)容的可讀性冤竹。
- 在進(jìn)制方面拂封,由于boolean使用true/false,所以不涉及bin/oct/dec/hex鹦蠕。
- boolean也無法與其他基本數(shù)據(jù)類型進(jìn)行強制轉(zhuǎn)化冒签。
- 由于只是true/false,所以可讀性方面也比較直接钟病。
2.4 運算操作
boolean數(shù)據(jù)類型擁有四種運算方式萧恕,如下表格
運算 | 非 | 與 | 或 | 異或 |
---|---|---|---|---|
符號 | !a | a & b | a | b | a ⊕ b |
示例 | !true = false | true & false = false | true | false = true | true ⊕ false = true |
一點小思考
最早的體現(xiàn)是計算機結(jié)構(gòu)中高低電平的0與1,在程序中肠阱,經(jīng)常會出現(xiàn)判斷結(jié)構(gòu)票唆,對兩者進(jìn)行判斷某一屬性是否相同的行為,判斷結(jié)果決定這程序的走向屹徘,此時真與假就很簡單的表示了兩種走向走趋。可以說是一種特殊的分支結(jié)構(gòu)噪伊。
3. byte short int long
這四種類型都可以看做是整數(shù)類型簿煌,區(qū)別在于表示范圍不同氮唯,給定一個n個bit(8*#ofbyte)的整數(shù)類型,可以表示的范圍為[-2n~2n-1]姨伟。
在Java的基本數(shù)據(jù)類型中惩琉,這四種類型默認(rèn)是有符號的,所以表示范圍包括負(fù)數(shù)和正數(shù)夺荒。當(dāng)然也可以將這些類型看作是無符號整數(shù)瞒渠,Java也支持無符號的運算操作。
3.1 類型存儲和計算方式
根據(jù)上文的表格可以很清晰的看出不同的整數(shù)類型占用了不同的字節(jié)技扼,這也是決定某個類型表示范圍的因素在孝。每個字節(jié)包含8個bits,其中每個bits有兩種狀態(tài)0或1淮摔。
存儲結(jié)構(gòu)中,不會有特殊的符號標(biāo)識正負(fù)號始赎。但是在運算過程中和橙,Java將第一個bit當(dāng)作符號位,0表示正數(shù)造垛,1表示負(fù)數(shù)魔招,從而在運算過程中整數(shù)類型就作為有符號數(shù)進(jìn)行運算。
并且在存儲結(jié)構(gòu)中五辽,數(shù)據(jù)是以補碼的形式存在办斑,正數(shù)的補碼是數(shù)據(jù)本身,負(fù)數(shù)的補碼是除符號位取反+1杆逗。之所以采用補碼乡翅,是為了在硬件上運算方便。
源碼和補碼的關(guān)系可以進(jìn)行如下的理解:
- 以byte類型為例罪郊,將數(shù)字從小到大排列蠕蚜,就是-128,-127...127悔橄。
- 源碼就是數(shù)字本身
- 補碼就是符號位加上每個數(shù)字的索引就是10000000靶累,10000001...
下面通過byte進(jìn)行舉例,其他類型除了占用內(nèi)存長度不同癣疟,其他性質(zhì)都相同挣柬。
正數(shù)123表示為:
0 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
---|
負(fù)數(shù)-57補碼表示為:
1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 |
---|
基本的計算方法就是加減乘除,其中減法其實是轉(zhuǎn)化為加法睛挚,通過減數(shù)加上被減數(shù)的相反數(shù)實現(xiàn)邪蛔。
- 加法:按位相加,與十進(jìn)制相同的進(jìn)位法則
- 減法:轉(zhuǎn)化為加法竞川,通過減數(shù)加上被減數(shù)的相反數(shù)實現(xiàn)
- 乘法:符號位進(jìn)行異或店溢,其他位進(jìn)行與十進(jìn)制相同的乘法運算
- 除法:符號位進(jìn)行異或叁熔,其他位進(jìn)行與十進(jìn)制相同的乘法運算
3.2 聲明和定義
聲明方法如下:
byte aByte = 2;
short aShort = 2;
int aInt = 2;
long aLong = 2L;
- 整數(shù)類型在進(jìn)行初始化賦值的時候正常賦值即可,唯一需要注意的是床牧,Java中任意一個常數(shù)都是先轉(zhuǎn)化為int荣回,再判斷是都在變量類型可表示的范圍里跌宛,再進(jìn)行自動的賦值洞坑。除非在常數(shù)末尾加上L,加上L表示直接轉(zhuǎn)化為long型常數(shù)蕊爵。
- 末尾的L也不是非得加著蛙,由下文可知其他類型可以自動轉(zhuǎn)化為long型删铃,但是就多出了轉(zhuǎn)化的步驟。
- 所有的變量在不進(jìn)行初始化賦值的情況下踏堡,默認(rèn)值為0猎唁,(某個方法內(nèi)部的本地變量不會賦默認(rèn)值)
- 變量命名規(guī)則依照J(rèn)ava規(guī)約即可
3.3 賦值
與boolean相同,賦值包括進(jìn)制顷蟆,類型之間的轉(zhuǎn)化诫隅,以及內(nèi)容的可讀性。
進(jìn)制 | bin | oct | dec | hex |
---|---|---|---|---|
前綴 | 0b | 0 | 1~9 | 0x |
- 進(jìn)制上帐偎,任何一種正數(shù)類型都可以指定bin/oct/dec/hex逐纬,不同的進(jìn)制通過不同的前綴區(qū)分。具體的前綴代號如上文表格削樊。不管使用何種進(jìn)制豁生,在給long型變量賦值的時候都需要在常數(shù)尾添上L。
- 類型之間的自動轉(zhuǎn)化漫贞,只能由低向高轉(zhuǎn)化(高指代表示范圍大的類型甸箱,低指代表示范圍小的類型),由高向低轉(zhuǎn)化需要進(jìn)行強制轉(zhuǎn)化迅脐,強制轉(zhuǎn)化的代碼如下摇肌。強轉(zhuǎn)的過程就是從高類型右側(cè)開始直接截取與低類型大小相同的字節(jié)作為低類型常量,顯然有可能并不代表原來的數(shù)據(jù)仪际。
high aHigh = xxx;
low aLow = (Low)aHigh;
- 為了使得長數(shù)據(jù)可讀性更高围小,Java可以在用于賦值的常數(shù)中間插入下劃線“_”,但是不能在前綴部分或者后綴(L)部分插入树碱,例如使用0b前綴的時候?qū)]四位二進(jìn)制位區(qū)分開來肯适,常數(shù)就可以寫成0b0101_0101_0101_0101_0101_0101_0101_0101。
3.4 運算操作
與計算方式不同成榜,運算操作包括可以進(jìn)行的運算框舔,以及運算的性質(zhì)。
- byte short int 類型在計算的時候都先轉(zhuǎn)化為int,然后再進(jìn)行計算刘绣,這也就導(dǎo)致一下的代碼會出現(xiàn)注釋中的錯誤樱溉。
byte aByte = 12;
byte bByte = aByte + aByte;
//Type mismatch: cannot convert from int to byte
- 在計算乘法的時候,如果結(jié)果溢出(超過int能表示的范圍)纬凤,那么將截取最后32位作為結(jié)果福贞。long類型同理,在大數(shù)進(jìn)行計算的時候停士,使用BigInteger封裝類進(jìn)行計算挖帘。
- 在計算除法的時候,整數(shù)與整數(shù)的除法只能整除
除了加減乘除運算恋技,整型數(shù)據(jù)還有左移(<<)拇舀,右移(>>),無符號右移(>>>)
- 左移蜻底,所有位依次向左移骄崩,右邊補0
- 右移,所有位依次向右移薄辅,左邊補與原符號位相同的數(shù)字
- 無符號右移刁赖,所有位依次向右移,左邊補0长搀。無符號右移就是為了應(yīng)對無符號類型的運算,例如涉及IP地址的運算鸡典。
一點小思考
看以下兩個賦值方式源请,第一位為符號位,另外7位為數(shù)字為
byte aByte = 0b0101_0101;
byte bByte = 0b1010_1010;
如果用這樣的方式賦值彻况,bByte
會報type mismatch
錯誤谁尸,為什么呢?
因為Java中所有的常數(shù)都是先轉(zhuǎn)化為int類型纽甘,再判斷值是否在聲明的變量可表示的范圍內(nèi)良蛮。那么0b1010_1010其實表示的數(shù)值是0b0000_0000_0000_0000_0000_0000_1010_1010,顯然不在bByte可表示的范圍內(nèi)悍赢,所以在轉(zhuǎn)化的時候會產(chǎn)生異常决瞳。并非想當(dāng)然的將第一個bit看作符號位。
4. float double
4.1 類型存儲和計算方式
參照IEEE 754-2019標(biāo)準(zhǔn)左权,可以看出浮點類型小數(shù)在計算機程序中的存儲方式皮胡。下面兩幅圖分別表示了,float和double類型的標(biāo)準(zhǔn)赏迟。
以float進(jìn)行舉例屡贺,sign為符號位,exponent為指數(shù)位或者階位,fraction為尾數(shù)位甩栈,計算方式為(sign&1)1.fraction*2^(exponent-127)
浮點數(shù)的加減分為五個步驟
- 對階泻仙,小階向大階對齊
- 尾數(shù)加減
- 規(guī)格化處理
- 舍入操作
- 判斷結(jié)果的正確性,是否溢出
浮點數(shù)的乘除分為兩個步驟
- 階碼運算量没,乘-階碼求和玉转,除-階碼求差
- 浮點數(shù)的尾數(shù)乘除法以及舍入處理
4.2 聲明和定義
聲明方法如下:
float aFloat = 1.23F;
double aDouble = 1.23D;
默認(rèn)值float為0.0F,double為0.0D允蜈,(某個方法內(nèi)部的本地變量不會賦默認(rèn)值)
4.3 賦值
- 與其他數(shù)值類型不同冤吨,浮點數(shù)只能通過十進(jìn)制進(jìn)行賦值
- int char short byte類型可以強轉(zhuǎn)為float,但是強轉(zhuǎn)之后的結(jié)果與原結(jié)果相同饶套,但當(dāng)int類型數(shù)值形式為0b01xx_xxxx_xxxx_xxxx_xxxx_xxxx_x01x_xxxx時會出現(xiàn)精度缺失漩蟆,因為float的尾數(shù)只能表示24個bit(包括小數(shù)點前一位)所以從這一位開始會被舍去。在Java中妓蛮,這一位舍去的方法是舍0進(jìn)1怠李,感興趣的可以參照IEEE 754。
- double類型與float類型同理蛤克。
4.4 運算操作
除了常規(guī)的加減乘除捺癞,浮點數(shù)不可以進(jìn)行左移右移等操作。
5. char
5.1 類型存儲和計算方式
char類型用兩個字節(jié)存儲构挤,代表了單個字符髓介,總共可以表示65535個字符。
雖然char類型只用來指代字符筋现,但也可以進(jìn)行計算唐础,計算得到的數(shù)字則表示該數(shù)值指代的字符。
5.2 聲明和定義
聲明方法如下:
char aChar='A';
- char類型在初始化賦值時可以使用單引號+字符的形式
- 默認(rèn)值為
'\u0000'
矾飞,(某個方法內(nèi)部的本地變量不會賦默認(rèn)值) - 變量命名也是依照J(rèn)ava規(guī)約
5.3 賦值
- char類型賦值形式可以使用單引號+字符
- 還可以使用字符代碼
\uxxxx
- 還可以直接使用數(shù)字
xxx
5.4 運算操作
所有整數(shù)可以進(jìn)行的操作一膨,char類型都可以適用,如下的例子洒沦,使用后的結(jié)果代表了結(jié)果指代的值豹绪。
char aChar='\u00ED';
aChar = (char) (aChar + 1);