java.io.PipedInputStream#receive(int) 源码:

protected synchronized void receive(int b) throws IOException {
    checkStateForReceive();
    writeSide = Thread.currentThread();
    if (in == out)
        awaitSpace();
    if (in < 0) {
        in = 0;
        out = 0;
    }
    buffer[in++] = (byte)(b & 0xFF);
    if (in >= buffer.length) {
        in = 0;
    }
}

先复习一下,原码反码补码这三个概念:
对于正数(00000001)原码来说,首位表示符号位,反码 补码都是本身;
对于负数(100000001)原码来说,反码是对原码除了符号位之外作取反运算即(111111110),补码是对反码作+1运算即(111111111)。

看一个 demo:

public class Test {
    public static void main(String[] args) {
        byte[] a = new byte[10];
        a[0]= -127;
        System.out.println(a[0]);
        int c = a[0]&0xff;
        System.out.println(c);
    }
}

输出:

-127
129

当将 -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进制的值必然是不同的,因为符号位位置已经发生了变化。

象例2中,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位,再参与运算。上面的 0xff 其实是 int 类型的字面量值,所以可以说 byte 与 int 进行运算。

解释来源:http://www.cnblogs.com/think-in-java/p/5527389.html