占用字節數 & 取值范圍
Java一共有8種基本數據類型(原始數據類型):
類型 存儲要求 范圍(包含) 默認值 包裝類 int 4字節(32位) -2^31~ 2^31-1 0 Integer short 2字節(16位) -215~215-1 0 Short long 8字節(64位) -2^63~2^63-1 0 Long byte 1字節(8位) -2^7~2^7-1 0 Byte float 4字節(32位) -3.4e+38 ~ 3.4e+38 0.0f Float double 8字節(64位) -1.7e+308 ~ 1.7e+308 0 Double char 2字節(16位) u0000~uFFFF(‘’~‘?’) ‘0’ Character boolean 1/8字節(1位) true, false FALSE Boolean
對於float與double類型:
內存結構:
float類型: 內存中共占4個字節,32bit位,其中bit位從高到低,依次是1位符號位、8位指數位、23位尾數位;
double類型:內存中共占8字節,64bit位,其中bit位從高到低,依次是1位符號位、11位指數位、52位尾數位;
大端模式與小端模式
大端模式是指數據的低位保存在內存的高地址中,而數據的高位保存在內存的低地址中.
小端模式是指數據的低位保存在內存的低地址中,而數據的高位保存在內存的高地址中。
大小端模式的由來
在計算機系統中,我們是以字節為單位的,每個地址單元都對應着一個字節,一個字節為8bit。但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器)。
另外,對於位數大於8位的處理器,例如16位或者32位的處理器,由於寄存器寬度大於一個字節,那么必然存在着一個如果將多個字節安排的問題。因此就導致了大端存儲模式和小端存儲模式。
大小端在內存中的存放方式舉例
例如:
a) 16bit寬的數0x1234
1.Little-endian模式CPU內存中的存放方式(假設從地址0x4000開始存放)為:
1 內存地址 2 0x4000 3 0x4001 4 存放內容 5 0x34 6 0x12
2.Big-endian模式CPU內存中的存放方式則為:
1 內存地址 2 0x4000 3 0x4001 4 存放內容 5 0x12 6 0x34
jvm使用的是大端
原碼、反碼、補碼知識
源碼
源碼就是數字對應的二進制表示。
負數的源碼 = 正數的源碼取反再加1
反碼
正數的反碼就是源碼自身。
負數的反碼就是:保持源碼符號位不變,其余各個位取反。
補碼
正數的補碼就是源碼自身。
負數的補碼就是: 反碼基礎上加1
如何根據補碼計算源碼:
- 最高位如果是0,即為正數,其補碼即為源碼;
- 最高位如果是1,即為負數,對此補碼再次計算補碼,結果即為源碼(即:補碼的補碼即為源碼)。
首先我們要都知道, &表示按位與,只有兩個位同時為1,才能得到1, 0x代表16進制數,0xff表示的數二進制1111 1111 占一個字節.和其進行&操作的數,最低8位,不會發生變化.
1. 只是為了取得低八位
通常配合移位操作符>>使用
例如:java socket通信中基於長度的成幀方法中,如果發送的信息長度小於65535字節,長度信息的字節定義為兩個字節長度。這時候將兩個字節長的長度信息,
以Big-Endian的方式寫到內存中
1 out.write((message.length>>8)&0xff);//取高八位寫入地址 2 out.write(message.length&0xff);//取低八位寫入高地址中
例如,有個數字 0x1234,如果只想將低8位寫入到內存中 0x1234&0xff
0x1234 表示為二進制 0001001000110100
0xff 表示為二進制 11111111
兩個數做與操作,顯然將0xff補充到16位,就是高位補0
此時0xff 為 0000000011111111
與操作 1&0 =0 1&1 =1 這樣 0x1234只能保留低八位的數 0000000000110100 也就是 0x34
2. 保證補碼的一致性
我們只關心二進制的機器數而不關注十進制的值,那么byte &0xff只是對其最低8位的復制,通常配合邏輯或 ‘’|’'使用,達到字節的拼接,但不保證其十進制真值不變
1 public static void main(String[] args) { 2 byte b = -127;//10000001 3 int a = b; 4 System.out.println(a); 5 a = b&0xff; 6 System.out.println(a); 7 }//輸出結果-127,129
乍一看,b是8位的二進制數,在與上0xff(也就是 11111111),不就是其本身嗎,輸出在控制台結果為什么是129呢?
首先計算機內的存儲都是按照補碼存儲的,-127補碼表示為 1000 0001
int a = b;將byte 類型提升為int時候,b的補碼提升為 32位,補碼的高位補1,也就是
1111 1111 1111 1111 1111 1111 1000 0001
負數的補碼轉為原碼,符號位不變,其他位取反,在加1,正數的補碼,反碼都是本身
結果是 1000 0000 0000 0000 0000 0000 0111 1111表示為十進制 也是 -127
也就是 當 byte -> int 能保證十進制數不變,但是有些時候比如文件流轉為byte數組時候,
我們不是關心的是十進制數有沒有變,而是補碼有沒有變,這時候需要&上0xff
本例子中,將byte轉為int 高24位必將補1,此時補碼顯然發生變化,在與上0xff,將高24重新置0,
這樣能保證補碼的一致性,當然由於符號位發生變化,表示的十進制數就會變了
1 1111 1111 1111 1111 1111 1111 1000 0001 2 3 & 4 5 0000 0000 0000 0000 0000 0000 1111 1111 6 7 結果是 8 9 0000 0000 0000 0000 0000 0000 1000 0001
和原來的補碼 一致,但是顯然符號位變化了,表示的十進制數發生變化,變為129
結論:
java中基本類型從小擴展到大的數據類型時候,正數因為符號位是0,無論如何都是補零擴展,但是負數補零擴展和補符號位擴展完全不同,
負數補符號位擴展,保證十進制數不變
例如 byte>>>int -127自動按照補符號位擴展,在高24位補符號位1,表示的十進制數不變
補零擴展,保證補碼的一致性,但是表示的十進制發生變化
例如,本例中byte提升為int,&0xff的操作