面对带正负号的数,会采用符号扩展,如果原值是正数,则高位补上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扩展,所以在二进制存储和十进制数值上都能保证一致。

byte为什么要与0xff的更多相关文章

  1. Java中byte转换int时与0xff进行与运算的原因

    http://w.baike.com/LGAdcWgJBBQxRAHUf.html 转帖 java中byte转换int时为何与0xff进行与运算 在剖析该问题前请看如下代码 public static ...

  2. java中byte, int的转换

    最近在做些与编解码相关的事情,又遇到了byte和int的转换,看着那些关于反码.补码的说明依旧头疼,还是记下些实用的方法吧.int -> byte可以直接使用强制类型转换: byte b = ( ...

  3. int跟byte[]数组互转的方法,整数 + 浮点型

    整数: int转byte数组 public static byte[] intToBytes2(int n){ ]; ;i < ;i++) { b[i]=(-i*)); } return b; ...

  4. byte和hexstring,int,string等的转换类

    public class HexConversion { /** * 16进制数的字符串转字节数组(16进制转字节数组) * * @param hexString * 16进制字符串 * @retur ...

  5. 【转】java中float与byte[]的互转 -- 不错

    原文网址:http://tjmljw.iteye.com/blog/1767716 起因:想把一个float[]转换成内存数据,查了一下,下面两个方法可以将float转成byte[]. 方法一 imp ...

  6. 【转】java中byte, int的转换, byte String转换

    原文网址:http://freewind886.blog.163.com/blog/static/661924642011810236100/ 最近在做些与编解码相关的事情,又遇到了byte和int的 ...

  7. 为何与0xff进行与运算

    为何与0xff进行与运算 在剖析该问题前请看如下代码 public static String bytes2HexString(byte[] b) { String ret = "" ...

  8. 基本类型数据转换(int,char,byte)

    public class DataUtil { public static void main(String[] args) { int a = 8; int value = charToInt(by ...

  9. 各类型转换成byte[] 和HexString

    public class ByteUtil    {        /// <summary>        /// string >>Length        /// &l ...

随机推荐

  1. 阿里云 消息队列mq

    使用阿里云消息队列 控制台地址:http://ons.console.aliyun.com/#/home/topic Demo: 支付消息mq工厂类: public class DfacePayCon ...

  2. VINS 估计器之优化与边缘化

    VINS的优化除了添加了投影残差,回环检测残差,还有IMU的残差,边缘化产生的先验信息残差等.有些比较难理解,可参考此博客和知乎回答. void Estimator::optimization() { ...

  3. Python基础篇(初始函数)

    Python初始函数: 一.什么是函数 1.我们到目前为止, 已经可以完成一些软件的基础功能了. 那么我们来完成这样一个功 能: 约x: print("拿出手机") print(& ...

  4. 三、Json方式函数

    一.Json方式函数 // 4. 查看对象信息 console.dir(obj) =>可以显示一个对象所有的属性和方法. var info = { blog: "http://cllg ...

  5. Android开发中怎样用多进程、用多进程的好处、多进程的缺陷、解决方法(转)

    转自:http://blog.csdn.net/spencer_hale/article/details/54968092 1.怎样用多进程 Android多进程概念:一般情况下,一个应用程序就是一个 ...

  6. java延迟队列

    大多数用到定时执行的功能都是用任务调度来做的,单身当碰到类似订餐业务/购物等这种业务就不好处理了,比如购物的订单功能,在你的订单管理中有N个订单,当订单超过十分钟未支付的时候自动释放购物车中的商品,订 ...

  7. 转 Tomcat访问日志详细配置

    配置http访问日志.Tomcat自带的能够记录的http访问日志已经很详细了取消下面这段的注释: <Valve className="org.apache.catalina.valv ...

  8. CNN基础三:预训练模型的微调

    上一节中,我们利用了预训练的VGG网络卷积基,来简单的提取了图像的特征,并用这些特征作为输入,训练了一个小分类器. 这种方法好处在于简单粗暴,特征提取部分的卷积基不需要训练.但缺点在于,一是别人的模型 ...

  9. webpack第一节(2)

    安装webpack在文件夹中 安装完成如图所示 牛刀小试 在webpack-test根目录下新建一个hello.js (不新建在node-modules文件夹下面的目的是,该文件夹是webpack的依 ...

  10. pycharm查找替换快捷键

    查找:CTRL + F 替换:CTRL + R 如果想删除,替换那一栏不填就可以了