必须用 & 0xFF 是因为 Java byte 有符号,值≥128时存为负数,直接位运算会符号扩展破坏位模式;& 0xFF 将其转为无符号 int 值,确保位运算正确。

直接对 IP 字节做 & 运算容易出错,关键在于 Java 的 byte 是有符号类型。比如 (byte)0xFF 实际值是 -1,参与运算时会符号扩展成 0xFFFFFFFF,导致结果异常。必须先转成无符号整数再与掩码字节运算。
为什么必须用 & 0xFF 强转
Java 中 byte 范围是 -128 ~ 127,而 IP 和掩码的合法字节值是 0 ~ 255。当字节值 ≥ 128(如 192、224、255)被读作 byte 时,实际存储为负数。不做处理直接参与位运算,JVM 会自动将其提升为 int 并进行符号扩展,破坏原始位模式。
- 错误示例:
byte b = (byte)224; int x = b & 0xFF00;→b扩展为0xFFFFFFE0,& 0xFF00得0xFF00,完全不是预期的 224 - 正确做法:
int unsignedB = b & 0xFF;→ 得到干净的 224(int类型),可安全用于后续位操作
提取单字节子网段(如第三段网络号)
目标:从 IP 172.16.32.5 和掩码 255.255.224.0(/19)中提取第三字节对应的子网起始值(即 32)。
- 取 IP 第三字节:
byte ip3 = ipBytes[2];→ 值为32 - 取掩码第三字节:
byte mask3 = maskBytes[2];→ 实际是(byte)224,即 -32 - 分别强转:
int uIp3 = ip3 & 0xFF;,int uMask3 = mask3 & 0xFF; - 执行位与:
int net3 = uIp3 & uMask3;→32 & 224 = 32
完整提取四字节网络地址
封装为可复用方法,每字节都做显式无符号转换:
public static byte[] getNetworkAddress(byte[] ip, byte[] mask) {
if (ip.length != 4 || mask.length != 4) {
throw new IllegalArgumentException("IPv4 address and mask must be 4 bytes");
}
byte[] network = new byte[4];
for (int i = 0; i < 4; i++) {
int uIp = ip[i] & 0xFF;
int uMask = mask[i] & 0xFF;
network[i] = (byte) (uIp & uMask);
}
return network;
}
调用示例:byte[] ip = {(byte)192, (byte)168, (byte)5, (byte)120};byte[] mask = {(byte)255, (byte)255, (byte)255, (byte)0};
结果:{(byte)192, (byte)168, (byte)5, (byte)0} → 192.168.5.0
判断两个 IP 是否在同一子网
本质是比对网络地址是否一致,每字节都需强转后计算:
- 分别调用
getNetworkAddress(ip1, mask)和getNetworkAddress(ip2, mask) - 对两个结果数组逐字节比较:
net1[i] == net2[i](此时byte值已确保在 0~255 范围内,可直接比较) - 全部四字节相等,才属于同一子网

















