【Java基礎】Java的8種基本數據類型深入介紹

Java的8種基本數據類型介紹

基本數據類型存儲大小說明,在瞭解存儲大小說明之前我們先來了解幾個基本的概念:

  1. 位(bit):位表示的是二進制位,一般稱爲比特,是計算機存儲的最小單位。
  2. 字節(byte):字節是計算機中數據處理的基本單位。計算機中以字節爲單位存儲和解 釋信息,規定一個字節由八個二進制位構成,即1個字節等於8個比特(1Byte=8bit)。
  3. :計算機進行數據處理時,一次存取、加工和傳送的數據長度稱爲字(word)。一個字通常由一個或多個(一般是字節的整數位)字節構成。例如286微機的字由2個字節組成,它的字長爲16;486微機的字由4個字節組成,它的字長爲32位機。
  4. 字長:計算機的每個字所包含的位數稱爲字長。根據計算機的不同,字長有固定的和可變的兩種。固定字長,即字長度不論什麼情況都是固定不變的;可變字長,則在一定範圍內,其長度是可變的。計算的字長是指它一次可處理的二進制數字的數目。計算機處理數據的速率,自然和它一次能加工的位數以及進行運算的快慢有關。如果一臺計算機的字長是另一臺計算機的兩倍,即使兩臺計算機的速度相同,在相同的時間內,前者能做的工作是後者的兩倍。字長是衡量計算機性能的一個重要因素。

再來看看一張表吧,如下圖,每個類型都有一定的表示範圍,但是,在程序中有些計算會導致超出表示範圍,即溢出。溢出的時候並不會拋異常,也沒有任何提示。所以,在程序中,使用同類型的數據進行運算的時候,一定要注意數據溢出的問題。

數據類型 佔用字節數 初始值 取值範圍
byte 字節型 1字節(8bit) 0 -128~127(-27~ 27-1 )
char 字符型 2字節(16bit) ‘\u0000’ 採用unicode編碼,字符的存儲範圍在\u0000~\uFFFF
short 短整型 2字節(16bit) 0 -32768~32767(-215 ~ 215-1)
int 整型 4字節(32bit) 0 -231 ~ 231-1
long 長整型 8字節(64Bit) 0L -263 ~ 263-1
float 單精度浮點型 4字節(32bit) 0.0f 1.4e-45f ~3.4028235e+38f
double 雙精度浮點型 8字節(64bit) 0.0d 4.9e-324~1.7976931348623157e+308
boolean java未明確指出的大小(可能1bit、1byte、4byte) false true/false

由上表可以發現,boolean類型內存佔用情況Java並沒有明確定義,爲什麼呢?

因爲對虛擬機來說根本就不存在 boolean 這個類型,boolean類型在編譯後會使用其他數據類型來表示,那boolean類型究竟佔用多少個字節?帶着疑問,隨便網上一搜,答案五花八門,基本有以下幾種:

1、佔1個bit
理由是boolean類型的值只有true和false兩種邏輯值,在編譯後會使用1和0來表示,這兩個數在內存中只需要1位(bit)即可存儲,位是計算機最小的存儲單位。

2、佔1個字節
理由是雖然編譯後1和0只需佔用1位空間,但計算機處理數據的最小單位是1個字節,1個字節等於8位,實際存儲的空間是:用1個字節的最低位存儲,其他7位用0填補,如果值是true的話則存儲的二進制爲:0000 0001,如果是false的話則存儲的二進制爲:0000 0000。

3、佔4個字節
理由來源是《Java虛擬機規範》一書中的描述:“雖然定義了boolean這種數據類型,但是隻對它提供了非常有限的支持。在Java虛擬機中沒有任何供boolean值專用的字節碼指令,Java語言表達式所操作的boolean值,在編譯之後都使用Java虛擬機中的int數據類型來代替,而boolean數組將會被編碼成Java虛擬機的byte數組,每個元素boolean元素佔8位”。這樣我們可以得出boolean類型佔了單獨使用是4個字節,在數組中又是1個字節。

顯然第三條是更準確的說法,那虛擬機爲什麼要用int來代替boolean呢?爲什麼不用byte或short,這樣不是更節省內存空間嗎。大多數人都會很自然的這樣去想,我同樣也有這個疑問,經過查閱資料發現,使用int的原因是,對於當下32位的處理器(CPU)來說,一次處理數據是32位(這裏不是指的是32/64位系統,而是指CPU硬件層面),具有高效存取的特點。

最後的總結:
根據http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html官方文檔的描述:
boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its “size” isn’t something that’s precisely defined.
布爾類型:布爾數據類型只有兩個可能的值:真和假。使用此數據類型爲跟蹤真/假條件的簡單標記。這種數據類型就表示這一點信息,但是它的“大小”並不是精確定義的。
可以看出,boolean類型沒有給出精確的定義,《Java虛擬機規範》給出了4個字節,和boolean數組1個字節的定義,具體還要看虛擬機實現是否按照規範來,所以1個字節、4個字節都是有可能的。這其實是運算效率和存儲空間之間的博弈,兩者都非常的重要。

另外由上表可以看出,1byte=8bit(位),學過計算機的都瞭解,二進制中最高位代表符號位,那麼Java中,爲什麼byte類型的取值範圍爲【-128~127】而不是[-127,127]

在解釋這個問題之前我們需要了解幾個概念:機器數、真值、原碼、反碼、補碼

機器數:
一個數在計算機中的二進制表示形式, 叫做這個數的機器數。機器數是帶符號的,在計算機用一個數的最高位存放符號, 正數爲0, 負數爲1。

比如:十進制中的數 +3 ,計算機字長爲8位,轉換成二進制就是00000011。如果是 -3 ,就是 10000011 。那麼,這裏的 00000011 和 10000011 就是機器數。

真值:
因爲第一位是符號位,所以機器數的形式值就不等於真正的數值。例如上面的有符號數 10000011,其最高位1代表負,其真正數值是 -3 而不是形式值131(10000011轉換成十進制等於131)。所以,爲區別起見,將帶符號位的機器數對應的真正數值稱爲機器數的真值。

例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

原碼:
原碼就是符號位加上真值的絕對值, 即用第一位表示符號, 其餘位表示值. 比如如果是8位二進制:

[+1]原 = 0000 0001
[-1]原 = 1000 0001
第一位是符號位. 因爲第一位是符號位, 所以8位二進制數的取值範圍就是:[1111 1111 , 0111 1111]
即[-127 , 127]。原碼是人腦最容易理解和計算的表示方式.

反碼:
反碼的表示方法是:正數的反碼是其本身,負數的反碼是在其原碼的基礎上, 符號位不變,其餘各個位取反。

[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反

可見如果一個反碼錶示的是負數, 人腦無法直觀的看出來它的數值. 通常要將其轉換成原碼再計算.

補碼:
補碼的表示方法是:

正數的補碼就是其本身

負數的補碼是在其原碼的基礎上, 符號位不變, 其餘各位取反, 最後+1. (即在反碼的基礎上+1)

[+1] = [00000001]原 = [00000001]反 = [00000001]補
[-1] = [10000001]原 = [11111110]反 = [11111111]補

對於負數, 補碼錶示方式也是人腦無法直觀看出其數值的. 通常也需要轉換成原碼在計算其數值.

正數:
正數的反碼和補碼都與原碼相同
負數:
負數的反碼、補碼與原碼不同,負數的反碼:原碼中除去符號位,其他的數值位取反,0變1,1變0。負數的補碼:反碼+1

解釋:爲什麼byte類型的取值範圍爲-128~127?

現在我們知道了計算機可以有三種編碼方式表示一個數. 對於正數因爲三種編碼方式的結果都相同:

[+1] = [00000001]原 = [00000001]反 = [00000001]補

所以不需要過多解釋. 但是對於負數:

[-1] = [10000001]原 = [11111110]反 = [11111111]補

可見原碼, 反碼和補碼是完全不同的. 既然原碼纔是被人腦直接識別並用於計算表示方式, 爲何還會有反碼和補碼呢?

首先, 因爲人腦可以知道第一位是符號位, 在計算的時候我們會根據符號位, 選擇對真值區域的加減. (真值的概念在本文最開頭). 但是對於計算機, 加減乘數已經是最基礎的運算, 要設計的儘量簡單. 計算機辨別”符號位”顯然會讓計算機的基礎電路設計變得十分複雜! 於是人們想出了將符號位也參與運算的方法. 我們知道, 根據運算法則減去一個正數等於加上一個負數, 即: 1-1 = 1 + (-1) = 0 , 所以機器可以只有加法而沒有減法, 這樣計算機運算的設計就更簡單了.

於是人們開始探索 將符號位參與運算, 並且只保留加法的方法. 首先來看原碼:

計算十進制的表達式: 1-1=0

1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2

如果用原碼錶示, 讓符號位也參與計算, 顯然對於減法來說, 結果是不正確的.這也就是爲何計算機內部不使用原碼錶示一個數.

爲了解決原碼做減法的問題, 出現了反碼:

計算十進制的表達式: 1-1=0

1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0

發現用反碼計算減法, 結果的真值部分是正確的. 而唯一的問題其實就出現在”0”這個特殊的數值上. 雖然人們理解上+0和-0是一樣的, 但是0帶符號是沒有任何意義的. 而且會有[0000 0000]原和[1000 0000]原兩個編碼表示0.

於是補碼的出現, 解決了0的符號以及兩個編碼的問題:

1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 =[0000 0001]反 + [1111 1110]反= [0000 0001]補 + [1111 1111]補 = [0000 0000]補=[0000 0000]原

這樣0用[0000 0000]表示, 而以前出現問題的-0則不存在了.而且可以用[1000 0000]表示-128:

(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]補 + [1000 0001]補 = [1000 0000]補

-1-127的結果應該是-128, 在用補碼運算的結果中, [1000 0000]補 就是-128. 但是注意因爲實際上是使用以前的-0的補碼來表示-128, 所以-128並沒有原碼和反碼錶示.(對-128的補碼錶示[1000 0000]補算出來的原碼是[0000 0000]原, 這是不正確的),使用補碼, 不僅僅修復了0的符號以及存在兩個編碼的問題, 而且還能夠多表示一個最低數. 這就是爲什麼8位二進制, 使用原碼或反碼錶示的範圍爲[-127, +127], 而使用補碼錶示的範圍爲[-128, 127]。

因爲機器使用補碼, 所以對於編程中常用到的32位int類型, 可以表示範圍是: [-231, 231-1] 因爲第一位表示的是符號位.而使用補碼錶示時又可以多保存一個最小值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章