Java中的byte & 0xff到底有什么作用?

先说结论

byte & 0xff 是将byte从(-128 至 127)转化成 int(转化后的数值范围: 0 至 255)。

其实就是1个byte有两种表示方法,我们既可以用-128 - 127这段范围来表示一个字节,也可以用 0 - 255这个范围的数来表示一个字节。

看一个demo

用Java中的InetAddress类来获取我当前的ip

public class InetAddressTest { 
    public static void main(String[] args) throws UnknownHostException {
        InetAddress localHost = InetAddress.getLocalHost();
        byte[] address = localHost.getAddress();
        for (byte b : address) {
            System.out.print(b + " ");
        }
    }
}

输出结果

-64 -88 2 119

本机ip
在这里插入图片描述

好像不太一样,我们ip地址只用 0 - 255来表示,不会出现负数。

所以再换一种写法,将取出来的字节 & 0xff

public class InetAddressTest { 
    public static void main(String[] args) throws UnknownHostException {
        InetAddress localHost = InetAddress.getLocalHost();
        byte[] address = localHost.getAddress();
        for (byte b : address) {
            System.out.print( ( b & 0xff ) + " ");
        }
    }
}

结果

192 168 2 119

Process finished with exit code 0

果然就是我们想要的结果

为什么需要转换

因为Java中的byte是有符号的,他的范围只能是 -128 - 127。

我们在使用tcp等协议的时候,首先要把传输的消息转化成字节流,然后再传输,在编程语言中字节流通常用十进制的byte数组来表示。
在这里插入图片描述

假如我们就想用 0-255来表示一个字节,不想用负数,该怎么办呢?

可惜Java中没有 无符号字节(unsigned byte), 我们只能用 int 来存储0-255。

而int的范围是(-2^31 ~ 2^31-1),只用了256个,剩下的空间都被浪费了,得不偿失啊。

所以我们存储的时候、传输的时候可以用byte,但是使用的时候就需要做一个转换了,那为什么0xff就可以得到无符号byte呢。

& 0xff的作用

作为一个十六进制数,0xff在Java中是用什么类型存储的呢?

在这里插入图片描述

应该显而易见吧,0xff是整型。

假设我现在要转化 字节 -1

-1的原码、反码、补码分别如下:

原码  1 0 0 0  0 0 0 1
反码  0 1 1 1  1 1 1 0
补码  0 1 1 1  1 1 1 1

现在和 0xff做运算, ff 就是(1111 11111),而因为他是整型,占4个字节,32为,所以0Xff的前面还有24个0。

用 -1 的补码进行计算

-1                                      0 1 1 1  1 1 1 1
0xff     000000000 000000000 000000000  1 1 1 1  1 1 1 1
=        000000000 000000000 000000000  0 1 1 1  1 1 1 1
=        255

其实在Java中,”任何数 & 0Xff等于那个数本身“ 这句话就显得不那么正确了

”任意整型 & 0xff = 本身“ 是没有问题的

但是字节 & 0xff 就被拖到了另一个次元,从byte进化成了int。

关于byte[ ] & 0xFF的问题

最近在写有关SHA256加密解密的问题,发现有一段代码是这样的,处于好奇理解了一下。

private static String byte2Hex(byte[] bytes){
  StringBuffer stringBuffer = new StringBuffer();
  String temp = null;
  for (int i=0;i<bytes.length;i++){
   temp = Integer.toHexString(bytes[i] & 0xFF);
   if (temp.length()==1){
    //1得到一位的进行补0操作
    stringBuffer.append("0");
   }
   stringBuffer.append(temp);
  }
  return stringBuffer.toString();
 }

Integer类中toHexString方法的参数是int类型,为什么byte[ ] & 0xFF可以表示int类型呢?

byte[i]是8位二进制,0xFF转化为8位二进制为11111111,& 之后的结果还是本身啊,这是怎么回事?

我们都知道计算机内的存储都是利用二进制的补码进行存储的。

复习一下,原码反码补码这三个概念

对于一个字节的最高位,计算机中是有规定的,正数的最高位为0,负数的最高位为1。

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

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

下面写段代码测试下

public static void main(String[] args) {
  byte[] a=new byte[10];
  a[0]=-127;
  System.out.println("a[0]:"+a[0]);
  int b=a[0] & 0xFF;
  System.out.println("b:"+b);
 }

得到的结果为:

a[0]:-127
b:129

现在针对这个结果进行分析:

byte类型的a[0]的值为-127,在计算机中存储的补码为:10000001,这个补码是8位的,而int类型是32位的,所以a[0]作为int类型来输出的时候jvm给做了个补位便成了 111111111111111111111111 10000001(-127),虽然补码转换了,但是这两个补码表示的十进制数字是相同的。

为了保证二进制数据的一致性,当byte要转化为int的时候,高的24位必然会补1,这样,其二进制补码其实已经不一致了,如果二进制被当作byte和int来解读,其10进制的值必然是不同的,因为符号位位置已经发生了变化,而&0xFF可以将高的24位置为0,低8位保持原样。

int b = a[0]&0xff; a[0]&0xff=1111111111111111111111111 10000001&11111111=000000000000000000000000 10000001 ,这个值就是129

所以最后显示的b的值为129

文章来源:
Java中的byte & 0xff到底有什么作用?
原文链接:https://blog.youkuaiyun.com/qq_37855749/article/details/115736609
但是好像被作者删除了
侵删

&lt;think&gt;好的,我现在要帮用户解答关于Javabyte数据类型的问题。首先,用户之前问过一个关于位操作的方法,现在接着问byte的数据类型,可能是因为他们想更深入理解那段代码中的字节数组操作。 用户的问题看起来是基础性的,但需要准确回答。Java中的byte是8位有符号整数,范围是-128到127。这点很重要,因为在之前的代码中,extract数组是byte类型的,所以每次操作一个字节的时候,需要知道它的数值范围。 接下来,我需要解释二进制补码表示,因为这是Javabyte存储的方式。用户可能对负数如何存储有疑问,所以举例子会有帮助,比如0xFFbyte中是-1,而直接赋值的话需要注意类型转换。 然后,应用场景部分,用户之前接触的是位操作和字节数组,所以需要强调byte在处理二进制数据、文件IO、网络传输中的用途。同时,提到图像处理、加密算法等实际应用,让用户明白为什么需要这种数据类型。 使用注意事项方面,类型转换和位运算的陷阱是关键。比如,进行位操作时,byte会被提升为int,这时候可能需要强制转换回来。还有无符号处理的问题,Java没有无符号byte,但可以通过&amp;0xFF来获得0到255的值。 最后,结合之前的代码,说明在addBit方法中如何通过操作byte数组来设置特定位,以及extractBitPos的位移操作如何影响字节中的各个位。这部分能帮助用户将理论应用到他们之前看到的代码中,加深理解。 要确保回答结构清晰,分点列出,使用例子来辅助说明,同时保持语言简洁易懂。避免使用过于专业的术语,但必要时要准确。检查是否有遗漏,比如byte的默认值,或者初始化时的注意事项,确保覆盖用户可能的问题点。&lt;/think&gt;在Java中,`byte`是一种**基本数据类型**,具体特性如下: --- ### 1. **基础定义** - **存储空间**:固定占用**8位(1字节)**的存储空间 - **数值范围**:有符号整数,范围为 **$-128$ 到 $127$**(含) - **二进制补码表示**:最高位为符号位(`0`表示正,`1`表示负) --- ### 2. **典型应用场景** | 场景 | 说明 | |-------------------|----------------------------------------------------------------------| | 二进制数据处理 | 处理文件、网络数据包等原始字节流时使用(如:`InputStream.read()`) | | 节省内存空间 | 当明确需要小范围整数时,替代`int`类型以优化内存占用 | | 硬件交互 | 与底层硬件(如传感器、寄存器)通信时直接映射二进制值 | | 加密算法 | 处理字节级别的加密/解密操作(如AES、SHA算法) | --- ### 3. **二进制操作示例** ```java byte b = 0b0010_1101; // 二进制字面量(Java 7+) int decimal = b &amp; 0xFF; // 转换为无符号值(0~255) ``` #### 位操作演示: ```java byte flags = 0b00000000; flags |= 0b00001000; // 设置第4位为1 &rarr; 0b00001000 (8) flags &amp;= ~0b00000100; // 清除第3位 &rarr; 0b00001000 (8) ``` --- ### 4. **关键注意事项** - **类型转换陷阱**: ```java byte a = 127; a += 1; // 编译通过,但实际值会溢出为-128 ``` - **无符号处理技巧**: ```java byte b = -1; int unsigned = b &amp; 0xFF; // 得到255(消除符号扩展影响) ``` - **默认值**:类成员变量默认值为`0`,局部变量必须显式初始化 --- ### 5. **与代码片段关联的解释 在您提供的`addBit`方法中: - `extract`作为`byte[]`数组,每个元素对应8个比特位 - `extractBitPos`使用十进制数值(128=0b10000000)控制比特位的设置 - **位移操作**(`&gt;&gt;=1`)实际上是在模拟二进制位的移动过程 --- ### 6. **内存布局示例 假设定义: ```java byte[] data = {0b00110011, (byte) 0b10000001}; ``` 其内存实际存储为: ``` 字节0: 00110011 (十进制51) 字节1: 10000001 (十进制-127,因补码表示) ``` --- ### 7. **与其他类型对比 | 类型 | 位数 | 范围 | 典型用途 | |--------|------|-----------------------|------------------------| | byte | 8 | $-128$ ~ $127$ | 原始字节数据 | | short | 16 | $-32768$ ~ $32767$ | 较少使用 | | int | 32 | $-2^{31}$ ~ $2^{31}-1$| 通用整数 | | char | 16 | Unicode字符 | 文本处理 | --- 掌握`byte`类型对于处理低级数据(如您提供的位操作代码)至关重要,它能直接映射到物理内存的二进制存储形式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值