中文转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