中文轉byte[]時變成了負數


在講解之前,先了解機器數、真值、原碼、反碼、補碼的概念

1、機器數

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

比如,十進制中的數 +3 ,計算機字長為8位,轉換成二進制就是00000011。如果是 -3 ,就是 10000011 。

那么,這里的 00000011 和 10000011 就是機器數。

2、真值

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

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

3、原碼

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

[+1] = 0000 0001

[-1] = 1000 0001

第一位是符號位. 因為第一位是符號位, 所以8位二進制數的取值范圍就是:[1111 1111 , 0111 1111],即[-127 , 127]

原碼是人腦最容易理解和計算的表示方式.

4、反碼

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

[+1] = [00000001] = [00000001]

[-1] = [10000001] = [11111110]

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

5、補碼

補碼的表示方法是:正數的補碼就是其本身。負數的補碼是在其原碼的基礎上, 符號位不變, 其余各位取反, 最后+1. (即在反碼的基礎上+1)

[+1] = [00000001] = [00000001] = [00000001]

[-1] = [10000001] = [11111110] = [11111111]

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

6、中文轉byte[]時變成了負數?

原因:漢字以補碼存儲

代碼演示:

public class FOSWrite1 {
    public static void main(String[] args) throws IOException {
        // 使用文件名稱創建流對象
        FileOutputStream fos = new FileOutputStream("fos.txt");
       // 字符串轉換為字節數組
       byte[] b = "黑".getBytes();
        for (int i = 0; i < b.length; i++) {
            System.out.println(b[i]);
        }
       // 寫出字節數組數據
       fos.write(b);
       // 關閉資源
        fos.close();
    }
}

結果如下:

-23
-69
-111

為什么中文的轉換成byte類型后 就變成了[-23, -69, -111]?

原理如下

在utf-8編碼中, 一個中文字符占用3個字節.
在GBK編碼中, 一個中文字符占用2個字節.

我們在這個網站查詢“黑”字的utf-8編碼16進制是 E9BB91 對應的二進制是‭11101001 10111011 10010001

二進制是帶符號位的, 我們需要給它們轉換成十進制, 步驟如下:

第一步: 由補碼得到反碼 (也就是二進制值減1)

注意:最高位由於都是1,故都是負數

進制 字節1 字節2 字節3
十六進制 E9 BB 91
補碼(二進制,負數) 1110 1001 1011 1011 1001 0001
(由補碼得到)反碼 1110 1000 1011 1010 1001 0000

E9轉換成二進制

第二步: 由反碼得到原碼(1變0, 0變1)

 

進制 字節1 字節2 字節3
十六進制 E9 BB 91
補碼(二進制,負數) 1110 1001 1011 1011 1001 0001
(由補碼得到)反碼 1110 1000 1011 1010 1001 0000
(將反碼變為)原碼 1001 0111 1100 0101 1110 1111

第三步: 將原碼轉換真值

進制 字節1 字節2 字節3
十六進制 E9 BB 91
補碼(二進制,負數) 1110 1001 1011 1011 1001 0001
(由補碼得到)反碼 1110 1000 1011 1010 1001 0000
(將反碼變為)原碼 1001 0111 1100 0101 1110 1111
真值 -23 -69 -111

總結:(1)、漢字以補碼存儲。(2)、一個漢字轉成字節數組會變成三個負數,每個負數表示一個字節,即一個漢字用三個字節表示。


免責聲明!

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



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