4-1 中的代码
while((b=in.read())!=-1){ if(b<=0xf){ //补0 System.out.print("0"); }
4-2
byte[] buf = new byte[20*1024]; int bytes = in.read(buf,0,buf.length); for (int i = 0; i <bytes ; i++) { if((buf[i]&0xff)<=0xf){ //补0 System.out.print("0"); }
read方法返回的是一个字节? 这里先假设是一个字节
buf[i]同样也是字节
都是一个byte和0xf比较,为什么第一个不需要&0xff
我觉得第一个例子也是要&0xff的
今天看的一些资料:
如果read()返回的是byte的话,那就会有负数。而"返回-1意味着结束",这个信息量用byte是无法表达的,所以必须用int。
也就是b=in.read()返回的实际上是一个int型的,如果是这样的话,byte确实不用0xff
第一个问题似乎有些眉目了,但是如果是这样的话,那么第二个buf[i]又是怎么回事?
buf[i]从处理上步骤上看需要&0xff,我推测buf[i]在比较之前需要先转为int型,负数前面全补1,所以为11111111 11111111 1111111 11111111,所以需要手动做0xff处理
不好意思,是我没有解释清楚。这个问题提的好!
首先我们贴出Java的源码:
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
注意返回值,read的返回值虽然是int,但是他是读取的byte&0xff得到的,而例2中,因为直接是byte,所以老师人为的加上了这一句。
现在问题实际上就变成了为什么不能直接和0x0f比较大小,而要加上& 0xff。以-1即就是11111111自己试一试就知道了,这个之前的回答已经解释过。
根据我粗浅的理解,Java源码中& 0xff这一句避免了在读取-1时函数返回-1而错误结束的情况,实际上这时会返回225。
我的理解:byte型参与运算时,默认提升为int型,0xff的作用是消除前面24位,转换为0得到后面8位。read()读第一个字节时,比如1011 1101,它会提升为int型,前面补0,是整数189。read(buf,0,buf.length)读取时,假如buf[0]是读取的第一个字节,byte型的负数,但当转换为二进制时为:11111111 11111111 11111111 10111101,前面是补1的,为负数,所以用0xff消除前面24个1,转换为0,得到后八位,是整数189。具体怎么实现,需要学习底层源码。
借用我另一个回答,不是很对口,但是可以解释;
凌晨来回答问题。
首先我们要弄明白,对于一个buf[i], 我们在什么情况下需要在输出之前补0,什么时候不需要补0.答案很清楚,如果它的高四位都是0,那么我们需要补,否则不需要。那么问题来了,怎么判断呢?
老师的代码是用buf[i] <= 0xf,可是代码结果不正确,会出现错误补0,也就是三个数字一起的情况。如果buf[i] == 0xff, 那么按程序是需要补0,因为作为一个byte,0xff实际上等于-1, 那么自然也小于0xf,因为0xf代表15.这就是出错的问题。
if判定语句改为((buf&oxff)<=oxf)之后,实际上结果就正确了。因为在Java中整数默认是int,也就是4个字节。因为有buf[i] & 0xff, 注意这里0xff 是4个字节的int类型,那么计算之前会把buf[i]自动进行类型转换,结果也是int类型,所以我们最终的到的结果是24位0加上原先的8位buf[i]。这时候的结果已经绝对是个正数,此时要判断buf[i]高4位是否有1,就看他和0xf的大小就行了。这里要设计一点补码的知识,我们还是以buf[i] == 0xff为例:
((buf&oxff)<=oxf)之后的结果是0x000000ff, 显然是大于0xf,所以没有补0.
实际上,我们也可以这么判断:buf[i] & 0xf0 == 0;这样的结果会保留buf[i]的高四位,其他位都是0,比较容易理解。
我觉得都可以,可能只是讲解者随意了
因为while啊