java位运算和字节编码(一)

成倅
• 阅读 6712

我们都知道计算机存储的是二进制,长度是8个比特。

byte b = 10;
int i = -10;
long l = 10L;

那么以上几个变量如何用二进制表示呢?
很多人第一印象肯定是 b变量占用一个字节,也就是8位,所以 b用二进制表示就是 1010,高位补零,所以是 00001010。那么i是int,占用4个字节,也就是32位,但因为是负数,所以最高位是100000000 00000000 00000000 00001010。同理 l变量则是 00000000 00000000 00000000 00000000 000000000 00000000 00000000 00001010。

上面的推理过程中存在一处错误,就是在java中存储的是补码,而不是原码。正数的原码,反码和补码相同。负数则不是一样。以上面 int i = -10 作为例子。

变量 i
原码 1000 1010
# 反码是符号位不变,其他位取反
反码 1111 0101
#补码则是在反码的基础上加1
补码 1111 0110

所以-10 在计算机中正确的表示应该是 1111 0110。
上面我们已经学习原码,反码和补码相关的概念,至于为什么要用补码,感兴趣的可以自己去查。

我们也知道在网络传输中,存储的就是二进制相关的byte数组。那么现在我们需要往消息中写入int或者long相关的信息,如何转换为byte数组中的相关项?第一个想到的办法就是强制转换。

int x = 135;
System.out.println((byte)x);  /** 输出-121 **/

x = -135;
System.out.println((byte)x); /** 输出-121 **/

可见输出的答案并不如你所愿。想知道为什么这样吗?感兴趣的可以自己去推导。
额,还是帮你们推导一遍吧。我们以 -135为例。
首先我们知道 int 占用4个字节,而byte占用1个字节,同时你也看到 -135已经超出了一个字节所能表示的范围[-128, 127]。如果强制转换后还能显示出正确结果,那才恐怖啊。

-135

原码 10000000 00000000 00000000 10000111

反码 11111111 11111111 11111111 01111000

补码 11111111 11111111 11111111 01111001

我们知道java中存储的是补码,可是因为byte只占一个字节,所以转换的时候只取到最低位那个字节也就是 01111001作为转换后补码存在。因为正数的原码和补码相同,也即是这个字节的原码是01111001,原值是 121。

刚才我们讨论的是int强制转换成byte类型可能存在的问题。那么如果我需要把byte类型的强制转换成int类型的会出现什么样的问题。

byte num = 120;        
System.out.println((int)num); 
num = -120;
System.out.println((int)num);

大家看到这两行示例代码时。尽量自己尝试推导出结果来,不要看我下面的推导过程。
我们以-120作为例子,尝试推导下(看到没有,我喜欢负数)。

-120

原码 11111000

反码 10000111

补码 10001000

##此刻开始转换为int类型,占4个字节,符号位1,用1填充高位三个字节。如果符号位是0,高位会用0填充。

补码 11111111 11111111 11111111 10001000 /** 存储在内存中的int整形补码 **/
反码 11111111 11111111 11111111 10000111
原码 10000000 00000000 00000000 01111000 
原值 -120

所以 当 byte num = -120 时, (int)num = -120
我相信很多人都没有自己推导,直接看我的推导的。那么再给你个机会,尝试推导下当byte num = 120的时候推导过程。

通过byte强制转换成int 好像一切都很顺利,也没有int强制转换成byte相关的问题。
当真的是那样吗?下一篇我们继续探讨这个话题。

原文链接 http://segmentfault.com/a/1190000003758605/

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java的char类型真的可以存汉字么?
今天偶尔看到一句话:ANSI编码表示英文字符时用一个字节,表示中文用两个字节,而unicode不管表示英文字符还是中文都是用两个字节来表示。我突然间对自己之前对java变量以Unicode编码存储产生了疑问。到底是以Unicode编码存储的还是和源文件使用的编码格式相同呢?联想到之前的一个问题java的char类型是否可以存储汉字,这个问题是
Wesley13 Wesley13
3年前
java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题
一.二进制,位运算,移位运算1.二进制对于原码,反码,补码而言,需要注意以下几点:(1).Java中没有无符号数,换言之,Java中的数都是有符号的;(2).二进制的最高位是符号位,0表示正数,1表示负数;(3).正数的原码,反码,补码都一样;(4).负数的反码它的原码符号位不变,其他位取反;(5).
Wesley13 Wesley13
3年前
C语言位运算
一、掩码运算1.什么是掩码?计算机中最小的单位是字节,一个字节代表8个二进制位。在实际的应用中许多信息并不需要使用一个字节来表示。例如表示当前系统运行是否正常,这种标志的取值只有0和1两种。因此使用是个完整的字节保存该标志就很浪费了。这些标志为是以位的形式存储的,因此当需要提取这些标志位的时候就需要使用掩码。掩码是人为生成的整数值,
Wesley13 Wesley13
3年前
Java中的位运算及简单的算法应用介绍
\TOC\Java中的位运算及简单的算法应用介绍众所周知,计算机底层是二进制。而java作为一门计算机编程语言,也对二进制的位运算提供了完整的支持。在java中,int是32位的,也就是说可以用来实现32位的位运算。方便起见,我们一般用16进制对它赋值,比如:0011表示成16进制是0x3,110111表示成16进制是0x37。
Stella981 Stella981
3年前
20180109Java位运算
一,Java位运算1.表示方法:  在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。 (1)正数的最高位为0,其余各位代表数值本身(二进制数)。 (2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。 2.位运算符位运算表达式由
可莉 可莉
3年前
20180109Java位运算
一,Java位运算1.表示方法:  在Java语言中,二进制数使用补码表示,最高位为符号位,正数的符号位为0,负数为1。补码的表示需要满足如下要求。 (1)正数的最高位为0,其余各位代表数值本身(二进制数)。 (2)对于负数,通过对该数绝对值的补码按位取反,再对整个数加1。 2.位运算符位运算表达式由
Wesley13 Wesley13
3年前
JAVA入门(二)
计算机存储数据都是010101这样用二进制存储的,这与我们的生活认知是不一样的,所以我们会把数据分成不同的数据类型,来方便我们进行编程,在底层由高级语言进行编码成二进制来进行与计算机交互。我们常说的字节是一种数据计量单位,1字节8个计算机位。计算机编码集随着计算机的普及与发展,各个国家对自己的语言进行编码,也是就有了许多的编码集。一般我们比较常
Wesley13 Wesley13
3年前
CPU中的二进制数据(整数篇)
1.用二进制数表示计算机信息的原因计算机内部CPU和内存都是IC的一种,它们都有多个引脚。IC的所有引脚,只有直流电压0V或5V两个状态。也就是说,IC的一个引脚,只能表示两个状态。IC的这个特性,决定了计算机的信息数据只能用二进制数来处理。计算机处理信息的最小单位——位,就相当于二进制中的一位。对于用二进制数表示
Stella981 Stella981
3年前
ASCII,Unicode和UTF
一、ASCII码我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从00000000到11111111。上
Wesley13 Wesley13
3年前
ES6(六)数值的扩展
二进制和八进制表示法ES6提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)(二进制binary)和0o(或0O)(八进制octonary)表示。0b111110111503//true0o767503//true从ES5开始,在严格模式之中,八进制就不再允许使用前缀0表示,E
Wesley13 Wesley13
3年前
utf8编码
utf8编码关于编码问题:首先需要知道什么是编码为什么要编码,计算机只能存储一个字节一个字节的二进制信息,所以需要把人可读的这些文字用唯一的方式在计算机内部表示出来,但是表示的方法不唯一;例如英文字符就那么点所以一个字节也就是8个二进制位就能给所有的进行编码,最多能给256个符号编码;但是ASCII编码实际只使用了