今天無(wú)意中看了下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));
}
頓時(shí)覺得很困惑,為什么數(shù)組里的第一個(gè)元素直接進(jìn)行移位運(yùn)算舰始,而后面的都和255進(jìn)行了與運(yùn)算呢崇棠?
當(dāng)時(shí)覺得困惑的原因是因?yàn)閎yte類型轉(zhuǎn)成int類型應(yīng)該不用做任何處理的,后來(lái)查了下資料后獲得了靈感丸卷,找到了原因枕稀。
原因是這樣的,在將輸入流的內(nèi)容讀取到byte數(shù)組時(shí)谜嫉,會(huì)進(jìn)行截?cái)辔馈R驗(yàn)檩斎肓髯x取時(shí),雖然是按byte讀取的沐兰,但是是以int類型返回哆档,且數(shù)據(jù)范圍是1~255,除非到了輸入流結(jié)束時(shí)住闯,返回才是-1瓜浸。所以在將數(shù)據(jù)讀取到byte數(shù)組澳淑,不可避免會(huì)進(jìn)行截?cái)啵瑢?duì)于一般的數(shù)據(jù)可能沒有問(wèn)題插佛,但是對(duì)于255這樣高位以1開頭的數(shù)據(jù)偶惠,會(huì)有問(wèn)題。因?yàn)閖ava都是有符號(hào)數(shù)朗涩,開頭為1代表是負(fù)數(shù)忽孽。這樣,在readLong()里谢床,對(duì)數(shù)據(jù)元素進(jìn)行移位時(shí)兄一,會(huì)默認(rèn)轉(zhuǎn)換成int型,這樣就導(dǎo)致byte型的255轉(zhuǎn)成int型后识腿,高位依舊為1(實(shí)際上代表的是-1了)出革。這樣并不是我們想要的。實(shí)際上需要對(duì)這些元素進(jìn)行無(wú)符號(hào)擴(kuò)展渡讼,也就是高位補(bǔ)0骂束。這就是為什么都要和255做與運(yùn)算的原因。同樣成箫,可以考慮下為什么第一個(gè)元素沒有進(jìn)行與運(yùn)算直接就移位了展箱?其實(shí)答案很簡(jiǎn)單,就是因?yàn)樵谧笠苿?dòng)56位后蹬昌,高位的8位數(shù)字必然是數(shù)組里的第一個(gè)元素混驰。
通過(guò)這個(gè),我們其實(shí)可以做一些無(wú)符號(hào)左移的操作皂贩。
byte[] bytes = new byte[] { (byte) -42 };
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
int i = input.read();
System.out.println("無(wú)符號(hào)數(shù):" + i);
System.out.println("無(wú)符號(hào)二進(jìn)制數(shù):" + Integer.toBinaryString(i));
另外可以用更簡(jiǎn)單的方式:
byte b = (byte) -42;
int result = (b & 0xFF);
System.out.println("無(wú)符號(hào)數(shù):" + result);
System.out.println("無(wú)符號(hào)二進(jìn)制數(shù):" + Integer.toBinaryString(result));
這種方式就用到上面提到的與計(jì)算方式栖榨。
備注:
(long)readBuffer[0] << 56的運(yùn)算順序是先對(duì)readBuffer[0]向上轉(zhuǎn)型為long,然后做移位運(yùn)算明刷。
對(duì)于byte,short類型的變量婴栽,他們的值域是包括正負(fù)的,所以要得到無(wú)符號(hào)的int值就需要和0xff,0xffff做與運(yùn)算辈末,其目的是保留低位同時(shí)高位置零愚争。
對(duì)于char類型的變量,他的值域不包括負(fù)數(shù)本冲,所以直接強(qiáng)轉(zhuǎn)成int型就可以了准脂。
從DataInputStream的readShort()和readUnsignedShort()可以看出,在方法內(nèi)部都用了in.read(),得到了無(wú)符號(hào)的int,然后兩個(gè)int進(jìn)行拼接檬洞。最后如果是要shot值就直接向下轉(zhuǎn)型狸膏,如果是要得到無(wú)符號(hào)值,就返回int添怔。
public final short readShort() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (short)((ch1 << 8) + (ch2 << 0));
}
public final int readUnsignedShort() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
if ((ch1 | ch2) < 0)
throw new EOFException();
return (ch1 << 8) + (ch2 << 0);
}