全网最全1500份Java学习资料、500份BAT面试真题:
关注公众号,输入“面试题”,获取提取码!
第一种情况:signed/unsigned之间的转化
java中,除了char是unsigned 两个字节,用来表达UTF-16,此外byte/short/int/long都是signed的。
取值范围:
boolean:一字节
byte:(-128,127) 一字节
char:(0,65535) 两字节
short:(-32768,32767)两字节
那么在Java与别的语言编写的程序通信时,就可能涉及到signed/unsigned之间的转化。比如C写的socket传输unsigned数据
signed到unsigned的转化
//JDK 1.8中Byte.toUnsignedInt(byte x)public static int toUnsignedInt(byte x) { return ((int) x) & 0xff;//将高24位全部变成0,低8位保持不变}//JDK 1.8中Integer.toUnsignedLong((int x)public static long toUnsignedLong(int x) { return ((long) x) & 0xffffffffL;//将高32位全部变成0,低32位保持不变}
比较典型,经典的运用则是下面的:
//JDK1.8 ByteArrayInputStream read函数源码protected byte buf[];//用于缓存数据的数组//调用该函数会返回一个(0,255)的int类型数字,如果读到stream的end,则返回-1public synchronized int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1;//这里跟调用toUnsignedInt(byte x)的效果是一样的}
上面的源码可能有的人会犯迷糊
0xff的二进制是1111 1111 (8bit),一个byte也是8bit,
上面的操作buf[pos++] & 0xff是将一个byte类型的数字&0xff,那么得到的结果应该是还是这个byte类型数字本身呀?
可能你忽略了一个问题了:Java二元运算符的类型自动提升
也就是说buf[pos++] & 0xff这个运算中,buf[pos++]已经被自动提升为int了。
byte b = -20;System.out.println(b & 0xff);// 236final byte b2 = -20;final byte mask = (byte) 0xff;System.out.println(b2 & mask); // -20
第二种情况:byte转化为16进制String
在如下一段代码中有int v = src[i] & 0xFF这样的代码。
public static String bytesToHexString(byte[] src){ StringBuilder stringBuilder = new StringBuilder(""); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); }
这里做&0xff的原因是:
1.byte是1byte(8位),int是4byte(32位)表示的。
2.Java中是使用了补码的形式进行数据存储的。
3.java中byte数据转化为int数据时会自动补位,如果最高位(符号位)是0,则高24位全部补0,若是1,则高24位全部补1。
4.知道了上面的三点,就有:
byte -1的二进制为(补码):1111 1111 -->对应的16进制为0xFF
int -1的二进制为(补码):1111 1111 1111 1111 1111 1111 1111 1111 -->对应的16进制为0xFFFFFFFF
5.Integer.toHexString(int i)函数内部是通过传进来数字的二进制(补码形式)来进行转换的,因此如果不进行int v = src[i] & 0xFF;
则得到的结果就是0xFFFFFFFF。而&0xff只后,传入的参数的二进制就变为0000 0000 0000 0000 0000 0000 1111 1111(虽然这个数的值以不再是-1,但是将他进行转换得到的0xff才是我们需要的)
源码如下:
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) { int charPos = len; int radix = 1 << shift; int mask = radix - 1; do { buf[offset + --charPos] = Integer.digits[val & mask];//每次do-while循环都会取4位(从高位到低位),Integer.digits[]数组是十六进制的字符集 val >>>= shift; } while (val != 0 && charPos > 0); return charPos; }final static char[] digits = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' };
以上五点是全部原因。
·END·