持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情
了解了Byte,为什么出错概率还这么高
在操作Byte或者类型转换的时候,即使了解了原理,出错概率还是很高,这是因为简单的类型转换涉及到的知识点很多,不像json,很多框架一行代码就能解决。
为什么出错
因为操作byte的涉及的知识点很多,比如字节截取、大小端、位运算、带符号不带符号等等。
- 字节截取:使用
System.arraycopy方法 - 大小端:约定大小端模式
- 位运算:掌握左移、右移、与、或、非
- 带符号:不带符号转换成带符号的表达方法,需要处理
实践
1. byte转int
单片机用byte表达的是0-255;而java的byte表达的是 -128-127。怎么处理?
单片机实际要传给我们255的值,对应的二进制位 1111 1111;
Java中1111 1111由于java是带符号的,解析出来为-1。
错误的操作就是不经过处理直接使用。
正确的做法应该是经过转换,代码如下:
public static void main(String[] args) {
byte a = (byte) 0xff;
System.out.println("a:" + a); // -1
System.out.println("a:" + byteToInteger(a)); // 255,也就是0xff
}
/**
* 解决java中byte输出可能为负数的问题。
*/
public static Integer byteToInteger(byte b) {
return 0xff & b;
}
如果认真分析了理论,上面的代码就有个疑问,二进制原本就是 1111 1111, 那么&0xff,这个二进制还是1111 1111。
确实两个数都是1111 1111,但此时的数据结构一样了,&0xff之后得到的是整型。
在JAVA中,同样的二进制在不同的数据结构中的表现不一样,这就是java的巧妙之处
所以两个数的表示方式在java中应该这么表示: 根据有符号的标识,高位0代表正数,高位1代表负数,可以得到以下结果。
1111 1111 -> -1
0000 0000 0000 0000 0000 0000 1111 1111 -> 255
2. byte[]转short
short 等于两个字节,举例 :
单片机用两个字节表达的是0-65534;而java的byte表达的是-32768~32767。怎么处理?
原理与byte转int类似。
public static void main(String[] args) {
byte[] b = new byte[2];
b[0] = (byte) 0xff;
b[1] = (byte) 0xff;
System.out.println("b:" + byteToShortLittle(b)); // -1
System.out.println("b:" + shortToInteger(byteToShortLittle(b))); // 65535
}
/**
* 读取小端byte数组为short
*
* @param b
* @return
*/
public static short byteToShortLittle(byte[] b) {
return (short) (((b[1] << 8) | b[0] & 0xff));
}
/**
* short转integer(考虑到short可能会超出范围特殊处理下)
*
* @param s
* @return
*/
public static Integer shortToInteger(Short s) {
if (s < 0) {
return 65535 + 1 + s; // 为什么是65535+1,这是因为中间还有一个0,不然少算了
} else {
return new BigDecimal(s).intValue();
}
}
/**
* 读取大端byte数组为short
*
* @param b
* @return
*/
public static short byteToShortBig(byte[] b) {
return (short) (((b[0] << 8) | b[1] & 0xff));
}
完整的byte相关的工具类参见我之前的文章大小端模式