了解了Byte,为什么出错概率还这么高

194 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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相关的工具类参见我之前的文章大小端模式