byte为什么要与0xff

代码人生 代码人生     2022-11-04     308

关键词:

面对带正负号的数,会采用符号扩展,如果原值是正数,则高位补上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数组转float以及byte转其他类型时为什么要&0xff

staticfinalchar[]HEX_CHARS="0123456789abcdef".toCharArray();//转换为十六进制 publicstaticStringtoHexString(byte[]b) StringBuildersb=newStringBuilder(b.length<<2); for(bytex:b)//byte只有8位int则是32位x&oxff之后会转换为int类型 inthi=(x&0xf0)>>4;//处理高... 查看详情

为啥字节在java中不取0xff?

...在java中不取0xff?【英文标题】:Whywillbytenottake0xffinjava?为什么字节在java中不取0xff?【发布时间】:2013-09-1513:21:43【问题描述】:为什么java编译器不让我把0xff放入byte,0xff是8位长,正好是byte数据类型的大小。谁能解释一下为什... 查看详情

无符号1byte转int

在java基本类型中byte是有正负之分,它的取值范围-128到127,有时候在网络编程里我们只需要正数,于是会约定1byte是无符号的,它的取值范围在255-0。那么我们怎么将无符号的1byte转为int呢?int转4byte publicstaticbyte[]intToBytes(intdata) //... 查看详情

integer.tohexstring(byte&0xff)

...2位的电脑中数字都是以32位格式存放的,如果是要求一个byte(8位)类型的数字,对于int这种32位的整形,高24位具有随机性(从所有的数字形式来看,前面的24位取值并不确定,我把它视为具有一定的随机性,比如int型的整数,高24... 查看详情

java中byte转换int时为何与0xff进行与运算

在剖析该问题前请看如下代码 publicstaticStringbytes2HexString(byte[]b){ Stringret=""; for(inti=0;i<b.length;i++){  Stringhex=Integer.toHexString(b[i]&0xFF);  if(hex.length( 查看详情

java中byte数组转换int时为何与0xff进行与运算

在剖析该问题前请看如下代码publicstaticStringbytes2HexString(byte[]b)  Stringret="";  for(inti=0;i<b.length;i++)  Stringhex=Integer.toHexString(b[i]&0xFF);  if(hex.length()=&# 查看详情

java如何将stringsrc="ff"转为byte[]bt=(byte)0xff

java如何将stringsrc="ff"转为byte[]bt=(byte)0xff将字符串ff变为byte数组但是byte数值还是16进制的参考技术A我记得String有个toBytes还是Byte或者Arrays里面有个方法可以把String转byte数组,而且十六进制是用字符串表达的,就算byte存储... 查看详情

byte常用操作

/** *低位在前,高位在后 * *@paramdata *@return */ privatebyte[]intToBytes(intvalue){ byte[]src=newbyte[4]; src[3]=(byte)((value>>24)&0xFF); src[2]=(byte)((value>>16)&0xFF); src[1]=(byte 查看详情

使用 APDU C# 设置自己的身份验证密钥 MiFare Classic

...正在使用CardWerk的SMARTCARDAPI。如何使用APDU更改默认密钥((byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byt 查看详情

string.valueof()和tostring()方法

1publicstaticStringvalueOf(Objectobj){2return(obj==null)?"null":obj.toString();3}避免空指针将byte类型的的每一位都置1方法://方式1byteallBitsOne=(byte)0xFF;//方式2byteallBitsOne=0xFFFFFFFF;为什么方式1可以呢?因为 0xFF 这个32位整 查看详情

java十六进制转十进制

...System.out.println("返回的数是:"+hh);哪个大神给看看为什么到了256就不一样了!!!哪里出问题了?参考技术A你的程序在i>256时,one变成一位十六进制数了,前面缺了一个0.在i>256时,在one前面 查看详情

0xff(代码片段)

0xFF=00000000000000000000000011111111也就是说0xFF代表了一个byte位全为1,-1的补码(数据)。数值和数据是两个不同的概念。数值表示一个数的大小,而数据就是补码(因为计算机中是以补码形式存在的)。 byteb=-1;//表示在计算机中... 查看详情

如何实现字节命令类(代码片段)

...想创建一个用于控制PTZ摄像机的类。该命令通过网络作为byte[]发送到摄像机。有两个协议具有不同的命令和值,因此我将为每个协议创建一个类。最好为每个命令创建一个byte[]并在类中列出它们,并根据用户输入更改值。例如:... 查看详情

为何与0xff进行与运算

为何与0xff进行与运算为何与0xff进行与运算在剖析该问题前请看如下代码publicstaticStringbytes2HexString(byte[]b) Stringret=""; for(inti=0;i<b.length;i++)  Stringhex=Integer.toHexString(b[i]&0xFF); &n 查看详情

和0xff做与/&0xff/and0xff的作用是什么?

和0xff做与/&0xff/AND0xff的作用是什么?在代码开发过程中,我们可能会看到这样的代码,在拿到一个数后,对其低N位进行和全1的与运算,即类似于:foo=foo&0xff;将foo的低八位和0xff做与运算。从逻辑上讲,1&1==1,0&1= 查看详情

socket长连接,字节发送(代码片段)

...tream=socket.getOutputStream();PrintStreamdos=newPrintStream(outputStream);byte[]bsa=newbyte[1024];bsa[0]=(byte)0xFF;bsa[1]=(byte)0x00;bsa[2]=(byte)0x08;bsa[3]=(byte)0x63;bsa[4]=(byte)0x91;bsa[5]=(byte)0x89;bsa[6]=(byte)0x76;bsa[8]=(byte)0x18;bsa[18]=(byte)0xFB;dos.write(bsa);byte[]b=newbyte[1024];w... 查看详情

c语言byte类型typedefunsignedcharbyte[20];如何初始化

typedefunsignedcharbyte[20]; 这是重新定义一个新的变量类型byte,或者说是给unsignedchar[20]起了一个别名。其意思是定义一个新类型byte,这种类型是一个有20个无符号字符元素的数组。在定义之后,就可以用type进行变量定义了。如... 查看详情

java如何将十六进制0xff5100a5转换为无符号int值,貌似java不支持无符号数据?

...,就能得到正确的了。如下:希望哪位能给个详细的解释byteh1=(byte)0xA5;byteh2=(byte)0x00;byteh3=(byte)0x51;byteh4=(byte)0xFF;之前我是用写字符的方式char[]c=newchar[]0xA5,0x00,0x51,0xFF;你需要使用long来存储这个值,long在java里是64位整数,java确实... 查看详情