首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 基本類型與字節數組高效互轉工具類:ByteUtil 完整實現

     編輯:Java 相關知識

前言

在網絡通訊、文件存儲、數據庫 Blob 字段操作等場景中,Java 基本類型與 byte[] 互轉是高頻剛需。本文提供一個無依賴、高性能、覆蓋全類型的 ByteUtil 工具類,採用位運算實現零拷貝轉換,並解決浮點數精度、字符編碼等易踩坑點。

核心設計原則

  • 大端序:網絡字節序標準,高位在前,低位在後
  • 位運算:& 0xFF 取低 8 位,>> 8 右移 8 位,避免符號擴展問題
  • 統一入口:重載 getBytes()/getXxx() 方法,調用鏈路清晰

完整源碼實現

基本類型 → byte[]

public class ByteUtil {

    /** short (2 bytes) */
    public static byte[] getBytes(short data) {
        return new byte[] {
            (byte) (data & 0xFF),
            (byte) ((data >> 8) & 0xFF)
        };
    }

    /** char (2 bytes) - UTF-16BE */
    public static byte[] getBytes(char data) {
        return new byte[] {
            (byte) (data & 0xFF),
            (byte) ((data >> 8) & 0xFF)
        };
    }

    /** int (4 bytes) */
    public static byte[] getBytes(int data) {
        return new byte[] {
            (byte) (data & 0xFF),
            (byte) ((data >> 8) & 0xFF),
            (byte) ((data >> 16) & 0xFF),
            (byte) ((data >> 24) & 0xFF)
        };
    }

    /** long (8 bytes) */
    public static byte[] getBytes(long data) {
        byte[] bytes = new byte[8];
        for (int i = 0; i < 8; i++) {
            bytes[i] = (byte) ((data >> (i * 8)) & 0xFF);
        }
        return bytes;
    }

    /** float (4 bytes) - IEEE 754 */
    public static byte[] getBytes(float data) {
        return getBytes(Float.floatToIntBits(data));
    }

    /** double (8 bytes) - IEEE 754 */
    public static byte[] getBytes(double data) {
        return getBytes(Double.doubleToLongBits(data));
    }

    /** String → byte[] (指定編碼) */
    public static byte[] getBytes(String data, String charsetName) {
        try {
            return data.getBytes(Charset.forName(charsetName));
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported charset: " + charsetName, e);
        }
    }

    /** String → byte[] (默認 GBK) */
    public static byte[] getBytes(String data) {
        return getBytes(data, "GBK");
    }
}

byte[] → 基本類型

    /** byte[] → short */
    public static short getShort(byte[] bytes) {
        if (bytes.length < 2) throw new IllegalArgumentException("Need 2 bytes");
        return (short) ((bytes[0] & 0xFF) | ((bytes[1] & 0xFF) << 8));
    }

    /** byte[] → char */
    public static char getChar(byte[] bytes) {
        if (bytes.length < 2) throw new IllegalArgumentException("Need 2 bytes");
        return (char) ((bytes[0] & 0xFF) | ((bytes[1] & 0xFF) << 8));
    }

    /** byte[] → int */
    public static int getInt(byte[] bytes) {
        if (bytes.length < 4) throw new IllegalArgumentException("Need 4 bytes");
        return (bytes[0] & 0xFF) 
             | ((bytes[1] & 0xFF) << 8)
             | ((bytes[2] & 0xFF) << 16)
             | ((bytes[3] & 0xFF) << 24);
    }

    /** byte[] → long */
    public static long getLong(byte[] bytes) {
        if (bytes.length < 8) throw new IllegalArgumentException("Need 8 bytes");
        long val = 0;
        for (int i = 0; i < 8; i++) {
            val |= ((long) bytes[i] & 0xFF) << (i * 8);
        }
        return val;
    }

    /** byte[] → float */
    public static float getFloat(byte[] bytes) {
        return Float.intBitsToFloat(getInt(bytes));
    }

    /** byte[] → double */
    public static double getDouble(byte[] bytes) {
        return Double.longBitsToDouble(getLong(bytes));
    }

    /** byte[] → String (指定編碼) */
    public static String getString(byte[] bytes, String charsetName) {
        try {
            return new String(bytes, Charset.forName(charsetName));
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("Unsupported charset: " + charsetName, e);
        }
    }

    /** byte[] → String (默認 GBK) */
    public static String getString(byte[] bytes) {
        return getString(bytes, "GBK");
    }
}

關鍵技術點解析

1. 位運算防符號擴展

// 錯誤寫法:byte 有符號,直接左移會符號擴展
byte b = -1; // 0xFF
int wrong = b << 8; // 0xFFFF0000 (錯誤!)

// 正確寫法:& 0xFF 先轉無符號
int correct = (b & 0xFF) << 8; // 0x0000FF00 (正確!)

2. 浮點數位模式轉換

// float 32 位 IEEE 754 標準
float f = 1.5f;
int bits = Float.floatToIntBits(f); // 獲取位模式 0x3FC00000
byte[] bytes = getBytes(bits);      // 作為 int 寫入

// 反向還原
float restored = Float.intBitsToFloat(getInt(bytes)); // 精確還原 1.5f

3. 字符編碼陷阱

  • GBK:中文雙字節,兼容舊系統,默認編碼
  • UTF-8:中文三字節,國際標準,推薦新項目使用
  • ISO-8859-1:單字節,無損轉換,常用於二進制協議封裝

性能優化版(ByteBuffer 實現)

public class ByteUtilBuffer {
    // 線程不安全,高併發下需 ThreadLocal 或對象池
    private static final ThreadLocal BUFFER = ThreadLocal.withInitial(() -> ByteBuffer.allocate(8).order(ByteOrder.BIG_ENDIAN));

    public static byte[] getBytesInt(int value) {
        ByteBuffer bb = BUFFER.get();
        bb.clear();
        bb.putInt(value);
        return Arrays.copyOfRange(bb.array(), 0, 4);
    }

    public static int getInt(byte[] bytes, int offset) {
        ByteBuffer bb = BUFFER.get();
        bb.clear();
        bb.put(bytes, offset, 4);
        bb.flip();
        return bb.getInt();
    }
    // 其他類型同理...
}

單元測試驗證

@Test
public void testRoundTrip() {
    // 基本類型
    assertEquals((short) 122, ByteUtil.getShort(ByteUtil.getBytes((short) 122)));
    assertEquals(122, ByteUtil.getInt(ByteUtil.getBytes(122)));
    assertEquals(1222222L, ByteUtil.getLong(ByteUtil.getBytes(1222222L)));
    assertEquals('a', ByteUtil.getChar(ByteUtil.getBytes('a')));
    
    // 浮點數精度驗證
    assertEquals(122.22f, ByteUtil.getFloat(ByteUtil.getBytes(122.22f)), 0.0001f);
    assertEquals(122.22, ByteUtil.getDouble(ByteUtil.getBytes(122.22)), 0.0001);
    
    // 字符串編碼驗證
    String cn = "我是好孩子";
    assertEquals(cn, ByteUtil.getString(ByteUtil.getBytes(cn, "UTF-8"), "UTF-8"));
    assertEquals(cn, ByteUtil.getString(ByteUtil.getBytes(cn), "GBK")); // 默認 GBK
}

對比 JDK 原生方案

| 方案 | 優點 | 缺點 | 適用場景 | |------|------|------|----------| | ByteUtil (位運算) | 無依賴、可控、教學價值高 | 手寫易出錯、維護成本 | 學習理解、輕量項目、特殊協議 | | ByteBuffer | 高性能、支持大小端、鏈式調用 | 線程不安全、對象創建開銷 | 高性能網絡編程、Netty 等框架 | | DataOutputStream | 標準 API、自動擴容 | 僅支持 OutputStream、性能一般 | 文件寫入、簡單序列化 | | ObjectOutputStream | 支持任意對象圖 | 序列化體積大、版本敏感、不安全 | 緩存存儲、RMI 遠程調用 |

總結

ByteUtil 通過位運算實現了基本類型與字節數組的精確、高效雙向轉換。理解其核心原理——「大端序存儲、位掩碼去符號、IEEE 754 浮點數位模式轉換」,能幫助開發者在網絡協議解析、二進制文件處理、嵌入式通訊等場景中游刃有餘。生產環境建議優先使用 ByteBuffer 或成熟序列化框架(Protobuf、Kryo),僅在極簡依賴或教學場景下直接使用本工具類。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved