天天看點

[Java工具] 關于byte和int的轉換

需求

單片機通過Socket發送過來類似 { 0xff,0x0c ,0x80...}的byte數組,根據協定分為unsigned char 和signed char兩種類型。需要将int資料轉為兩個byte發送給單片機,或将單片機發來的2個byte轉化為int。

工具程式

/**
     * 将兩個byte資料轉化為有符号int
     * @param high : 高八位
     * @param low : 低八位
     * @return
     */
    public static int twoByteToSignedInt(byte high,byte low){
        return (high << 8) | low;
    }

    /**
     * 将兩個byte資料轉化為無符号int
     * @param high : 高八位
     * @param low : 低八位
     * @return
     */
    public static int twoByteToUnsignedInt(byte high,byte low){
        return ((high << 8) & 0xffff) | (low & 0x00ff);
    }
    /**
     * 将int轉換為兩個byte
     * @param numInt : 實際隻取其中的低16位二進制數
     * @return 長度為2的byte數組 ,byte[0]為高8位,byte[1]為低八位
     */
    public static byte[] intToTwoByte(int numInt){
        byte[] rest = new byte[2];
        if(numInt < -32768 || numInt > 32767){
            return null;
        }
        rest[0] = (byte)(numInt >> 8);//高8位
        rest[1] = (byte)(numInt & 0x00ff);//低8位

        return rest;
    }
           

解釋

  • 單片機發送過來的資料有 unsigned char 和 signed char 之分;而 Java 中的 byte(8位)、int(32位) 都是有符号的。
  • 計算機裡的數字,不管正負,其底層都是以補碼形式存在的!!
  • Java 的二進制采用補碼形式。比如 Java 裡的 Integer.toBinaryString(int) 函數,如果傳入負數,則隻會輸出其補碼形式,傳入正數則輸出原碼二進制數(正數補碼=原碼)。
  1. signed char 轉為 Java 的有符号 int

    參見函數 twoByteToSignedInt(byte high,byte low) 。由于在單片機中signed char也是以補碼形式存在,是以直接用位操作将兩個byte拼接為一個int即可。

  2. unsigned char 轉為 Java 的無符号 int

    參見函數 twoByteToUnsignedInt(byte high,byte low) 。那為什麼要按位與0xffff呢?因為byte->int會發生符号擴充,這在轉為有符号int時沒有影響,但在轉為無符号int時,符号擴充會造成數值出現誤差。

    具體來說,比如對于一個byte,如果不進行& 0xff,那麼當一個byte會轉換成int時,由于int是32位,而byte隻有8位這時會進行f符号擴充,例如補碼11111111的十進制數為-1,轉換為int時變為1111 1111 1111 1111 1111 1111 1111 1111(補碼)即0xffffffff但是這個數是不對的,這種補位就會造成誤差。和0xff相與後,高24比特就會被清0了,結果就對了。

  3. int 轉為 unsigned/signed char

    參見intToTwoByte(int numInt)。

    直接取int裡的低16位即可。因為無論正負,在單片機裡都是以補碼形式存在,不需要額外轉換。

參考

Java中的Byte轉為無符号的Integer Java中位元組與無符号數之間的轉換 java中無符号類型的解決方案