DataInputStream类readLong()引起的思考

    今天无意中看了下jdk中的DataInputStream类,然后看到readLong()方法,如下:

private byte readBuffer[] = new byte[8];

public final long readLong() throws IOException {
        readFully(readBuffer, 0, 8);
        return (((long)readBuffer[0] << 56) +
                ((long)(readBuffer[1] & 255) << 48) +
		((long)(readBuffer[2] & 255) << 40) +
                ((long)(readBuffer[3] & 255) << 32) +
                ((long)(readBuffer[4] & 255) << 24) +
                ((readBuffer[5] & 255) << 16) +
                ((readBuffer[6] & 255) <<  8) +
                ((readBuffer[7] & 255) <<  0));
    }

    顿时觉得很困惑,为什么数组里的第一个元素直接进行移位运算,而后面的都和255进行了与运算呢?

    当时觉得困惑的原因是因为byte类型转成int类型应该不用做任何处理的,后来查了下资料后获得了灵感,找到了原因。

    原因是这样的,在将输入流的内容读取到byte数组时,会进行截断。因为输入流读取时,虽然是按byte读取的,但是是以int类型返回,且数据范围是1~255,除非到了输入流结束时,返回才是-1。所以在将数据读取到byte数组,不可避免会进行截断,对于一般的数据可能没有问题,但是对于255这样高位以1开头的数据,会有问题。因为java都是有符号数,开头为1代表是负数。这样,在readLong()里,对数据元素进行移位时,会默认转换成int型,这样就导致byte型的255转成int型后,高位依旧为1(实际上代表的是-1了)。这样并不是我们想要的。实际上需要对这些元素进行无符号扩展,也就是高位补0。这就是为什么都要和255做与运算的原因。同样,可以考虑下为什么第一个元素没有进行与运算直接就移位了?其实答案很简单,就是因为在左移动56位后,高位的8位数字必然是数组里的第一个元素。

    通过这个,我们其实可以做一些无符号左移的操作。

byte[] bytes = new byte[] { (byte) -42 };
		ByteArrayInputStream input = new ByteArrayInputStream(bytes);
		int i = input.read(); 		
		System.out.println("无符号数:" + i);		
		System.out.println("无符号二进制数:"  + Integer.toBinaryString(i));

    另外可以用更简单的方式:

byte b = (byte) -42;
		int result = (b & 0xFF);
		System.out.println("无符号数:" + result);
		System.out.println("无符号二进制数:" + Integer.toBinaryString(result));

    这种方式就用到上面提到的与计算方式。


原文地址:https://www.cnblogs.com/riskyer/p/3290027.html