Java中int,short,byte都是有符号的,如果想处理无符号数,只有一个办法,用容量更大的类型替换,例如unsigned short就用int。唯一的例外是char,它本身就是无符号的,所以可以用char作为unsigned short。
那么从一个byte[]中怎么读取一个有符号的数呢?以unsigned short为例:
int unsignedShort ;
byte[] buf = getFromSomePlace();
int b1 = buf[0];
int b2 = buf[1];
unsignedShort = (((b1 & 0xff) << 8) | (b2 & 0xff))
那么,((b1 & 0xff) << 8)是什么意思呢?
首先, & 操作符会自动提升byte到int。
然后看b1&0xff的含义。大于2^15-1的无符号short,用两位byte表示,最高位为1。因为Java中都是有符号的数,最高位是符号位,为1表示负数。当byte扩充为int时,扩充位全都会变成1,b1 & 0xff就是将高位的1去掉。
最后是位移8位,和下一个byte拼接成unsigned short。
对于unsigned short,其实还可以用char存储:
char unsignedShort = (char) (b1 << 8 | b2);
我们去查看DataInput的javadoc,readUnsignedShort就是这样的。那位同学说了,我怎么去看DataInputStream的实现不是这样的,
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);
}
没有什么&0xff。问题就在in.read()。InputStream的read方法返回的是int,从api描述可以看出:
Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255.
可以看出,实际上返回的是一个无符号的byte,内部已经做了转换。我们可以看一个具体的实现,ByteArrayInputStream.read()
public int read() throws IOException {
if (closed) {
throw new IOException("Stream closed");
} else if (index >= limit) {
return -1; // EOF
} else {
return buffer[index++] & 0xff;
}
}
也就是说,Java中没有unsigned byte,InputStreamde read方法都统一返回int,所以DataInputStream中就不用再转换了。
没有评论:
发表评论