面对带正负号的数,会采用符号扩展,如果原值是正数,则高位补上0;如果原值是负数,高位补1。
二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。
当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。
计算机中的二进制则是一个非常微小的开关,用“开”来表示1,“关”来表示0。

我们都知道Java的基本数据类型内存中都有一个固定的位数(内存分配空间),如byte占8位,int占32位等。正因如此,当把一个低精度的数据类型转成一个高精度的数据类型时,必然会涉及到如何扩展位数的问题。这里有两种解决方案: 
(1)补零扩展:填充一定位数的0。 
(2)补符号位扩展:填充一定位数的符号位(非负数填充0,负数填充1)。 
  对于无符号类型(相当于都是非负数)与有符号类型中的非负数部分,这两种方法没有区别,都是填充0;对于有符号类型中的负数部分,这两种方法就会产生差异了,补零扩展会填充0,而补符号位扩展会填充1。下面将byte类型的-127转为int类型为例,探讨一下这两种方法的区别。 
  首先必须明确一些知识点:

  • 计算机是用补码来存储数字的;
  • 正数的补码等于原码;
  • 负数的补码等于反码+1;
  • 一个数的补码的补码等于原码。

  -127原码1111 1111,反码1000 0000,补码1000 0001。计算机存储的是1000 0001,用十六进制表示为0x81。


  当使用补零扩展时,结果为: 0000 0000 0000 0000 0000 0000 1000 0001 
  用十六进制表示为0x81。为了计算十进制值,计算它的补码,结果为: 0000 0000 0000 0000 0000 0000 1000 0001 
  将这个二进制数转成十进制的结果是129。


  当使用补符号位扩展时,结果为: 1111 1111 1111 1111 1111 1111 1000 0001 
  用十六进制表示为0xFFFFFF81。为了计算十进制值,计算它的补码,结果为: 1000 0000 0000 0000 0000 0000 0111 1111 
  将这个二进制数转成十进制的结果是-127。 
由此可以得出结论: 
(1)使用补零扩展能够保证二进制存储的一致性,但不能保证十进制值不变。 
(2)使用补符号位扩展能够保证十进制值不变,但不能保证二进制存储的一致性。


原码反码补码这三个概念

对于正数(00000001)原码来说,首位表示符号位,反码 补码都是本身

对于负数(100000001)原码来说,反码是对原码除了符号位之外作取反运算即(111111110),补码是对反码作+1运算即(111111111)

概念就这么简单。

当将-127赋值给a[0]时候,a[0]作为一个byte类型,其计算机存储的补码是10000001(8位)。

将a[0] 作为int类型向控制台输出的时候,jvm作了一个补位的处理,因为int类型是32位所以补位后的补码就是1111111111111111111111111 10000001(32位),这个32位二进制补码表示的也是-127.

发现没有,虽然byte->int计算机背后存储的二进制补码由10000001(8位)转化成了1111111111111111111111111 10000001(32位)很显然这两个补码表示的十进制数字依然是相同的。

但是我做byte->int的转化 所有时候都只是为了保持 十进制的一致性吗?

不一定吧?好比我们拿到的文件流转成byte数组,难道我们关心的是byte数组的十进制的值是多少吗?我们关心的是其背后二进制存储的补码吧

所以大家应该能猜到为什么byte类型的数字要&0xff再赋值给int类型,其本质原因就是想保持二进制补码的一致性。

当byte要转化为int的时候,高的24位必然会补1,这样,其二进制补码其实已经不一致了,&0xff可以将高的24位置为0,低8位保持原样。这样做的目的就是为了保证二进制数据的一致性。

当然拉,保证了二进制数据性的同时,如果二进制被当作byte和int来解读,其10进制的值必然是不同的,因为符号位位置已经发生了变化。

int c = a[0]&0xff;

a[0]&0xff=1111111111111111111111111 10000001&11111111=000000000000000000000000 10000001 ,这个值算一下就是129,

所以c的输出的值就是129。

有人问

为什么上面的式子中a[0]不是8位而是32位,因为当系统检测到byte可能会转化成int

或者说byte经过一些运算后会转化成int时,就会将byte的内存空间高位补1扩充到32位,再参与运算。

其实是从数字类型扩展到较宽的类型时,补零扩展还是补符号位扩展。
这是因为Java中只有有符号数,当byte扩展到short, int时,即正数都一样,因为为符号位是0,所以无论如何都是补零扩展;

但负数补零扩展和按符号位扩展结果完全不同。
补符号数,原数值不变。
补零时,相当于把有符号数看成无符号数,比如-127 = 0x81,看成无符号数就是129, 256 + (- 127) 
对于有符号数,从小扩展大时,需要用&0xff这样方式来确保是按补零扩展。
而从大向小处理,符号位自动无效,所以不用处理。

也就是说在byte向int扩展的时候,自动转型是按符号位扩展的,这样子能保证十进制的数值不会变化,

而&0xff是补0扩展的,这样子能保证二进制存储的一致性,但是十进制数值已经发生变化了。

也就是说按符号位扩展能保证十进制数值不变,补0扩展能保证二进制存储不会变。

而正数可以说是既按符号位扩展,又是补0扩展,所以在二进制存储和十进制数值上都能保证一致。

最新文章

  1. mysq大数据分页
  2. 【Unity3D游戏开发】之全局管理类的几种方式 (十六)
  3. jquery之html(),text()方法详解
  4. [转载]Android View.onMeasure方法的理解
  5. npm:Node.js的软件包管理器
  6. 排序之直接插入排序(Straight Insertion Sort)
  7. 调试exynos4412—ARM嵌入式Linux—LEDS/GPIO驱动之三
  8. 移植kl档,但调用默认Generic.kl解决的方法
  9. 关于Trie Tree简单实现
  10. iOS gcd 串行,并行,同步,异步代码研究
  11. JavaScript 数组最大值
  12. 【坑】linux目录软连接的相关操作--很容易误操作
  13. 如何在Windows 10上访问NFS的share
  14. div总在页面最顶端
  15. PHP数字字符串左侧补0、字符串填充和自动补齐的几种方法
  16. climbing stairs leetcode java
  17. WorldWind源码剖析系列:星球表面渲染类WorldSurfaceRenderer
  18. python 获取有关访问者的浏览器的 细节
  19. HDFS高可用性及其分布式系统思想基础
  20. 使用github客户端上传文件(瓜皮教程)

热门文章

  1. 49-python基础-python3-列表-常用列表统计函数-max()-min()-sum()
  2. 同步任务 AsyncTask 介绍
  3. kubernetes里面有时候centos源用不了
  4. Python之基本的日期与时间转换 datetime、 dateutil模块
  5. jvm主要组成部分及其作用
  6. django 邮箱发送
  7. CSS分组和嵌套选择器
  8. delphi 判断WIN8 , WIN8.1 , WIN10 系统版本
  9. ABP的新旧版本
  10. ceph-pg