杰瑞科技汇

java string 16进制

核心场景

  1. 16进制字符串 → 字节数组:将 "48656C6C6F" 转换为字节数组 [72, 101, 108, 108, 111]
  2. 字节数组 → 16进制字符串:将字节数组 [72, 101, 108, 108, 111] 转换为 "48656C6C6F"

使用 java.lang.Integerjava.lang.String (基础方法)

这是最基础的方法,适用于单个字节的转换,但需要手动处理循环和格式化。

java string 16进制-图1
(图片来源网络,侵删)

字节 → 16进制字符串

将一个字节(byte)转换为两位的16进制字符串。

public class HexUtils {
    /**
     * 将单个字节转换为两位的16进制字符串
     * @param b 字节
     * @return 16进制字符串 ( 0x0A -> "0A")
     */
    public static String byteToHex(byte b) {
        // Integer.toHexString() 会将 byte (有符号) 提升为 int (有符号)
        // 对于负数,它会得到类似 "ffffffa5" 的结果,所以需要与 0xFF 进行与运算
        // 来确保我们只取低8位,并得到一个正数。
        return String.format("%02X", b & 0xFF);
    }
    public static void main(String[] args) {
        byte b1 = 10;  // 0x0A
        byte b2 = -91; // 0xA5 (因为 -91 的二进制补码是 10100101)
        System.out.println("Byte 10 to Hex: " + byteToHex(b1));   // 输出: Byte 10 to Hex: 0A
        System.out.println("Byte -91 to Hex: " + byteToHex(b2));  // 输出: Byte -91 to Hex: A5
    }
}

说明

  • b & 0xFF:这是一个非常关键的操作,Java 的 byte 是有符号的(-128 到 127)。Integer.toHexString(b) 在处理负数时会产生不符合预期的结果,通过与 0xFF(二进制 11111111)进行按位与运算,可以强制将 byte 转换为一个无符号的 int 值(0 到 255),从而得到正确的16进制表示。
  • String.format("%02X", ...)
    • %X:将参数格式化为16进制大写字符串。
    • 02:确保输出总宽度为2位,如果不足,在前面补0。

16进制字符串 → 字节

将两位的16进制字符串转换为一个字节。

public class HexUtils {
    /**
     * 将两位的16进制字符串转换为字节
     * @param hexStr 16进制字符串 ( "0A")
     * @return 字节
     */
    public static byte hexToByte(String hexStr) {
        // Integer.parseInt() 将16进制字符串解析为int
        // 然后强制转换为byte,由于我们输入的是0-255,所以直接转换是安全的。
        return (byte) Integer.parseInt(hexStr, 16);
    }
    public static void main(String[] args) {
        String hexStr1 = "0A";
        String hexStr2 = "A5";
        System.out.println("Hex \"0A\" to Byte: " + hexToByte(hexStr1)); // 输出: Hex "0A" to Byte: 10
        System.out.println("Hex \"A5\" to Byte: " + hexToByte(hexStr2)); // 输出: Hex "A5" to Byte: -91
    }
}

处理字节数组与16进制字符串的转换 (常用)

在实际应用中,我们通常需要处理整个字节数组,使用上述基础方法,我们可以通过循环来实现,但 Java 提供了更便捷的工具类。

java string 16进制-图2
(图片来源网络,侵删)

字节数组 → 16进制字符串 (推荐)

使用 javax.xml.bind.DatatypeConverter (JDK 1.6 - 8) 或 java.util.Base64 (JDK 8+)。

方案 A: javax.xml.bind.DatatypeConverter (JDK 8及以下)

这是一个非常方便的旧版 API。

import javax.xml.bind.DatatypeConverter;
public class HexConverter {
    public static String bytesToHex(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        // DatatypeConverter 提供了直接转换的方法
        return DatatypeConverter.printHexBinary(bytes);
    }
    public static void main(String[] args) {
        String originalString = "Hello, Java!";
        byte[] byteArray = originalString.getBytes(); // 默认使用平台编码 (通常是UTF-8)
        String hexString = bytesToHex(byteArray);
        System.out.println("Original String: " + originalString);
        System.out.println("Byte Array to Hex: " + hexString); // 输出: 48656C6C6F2C204A61766121
    }
}

方案 B: java.util.Base64 (JDK 8+) (不推荐用于16进制,但常被提及)

注意Base64 类主要用于 Base64 编码,而不是16进制,虽然它有一些 encodeToString 方法,但不适用于标准的16进制转换,请忽略 Base64 用于16进制的用法。

方案 C: 手动循环 (理解原理)

如果不想依赖外部库,可以自己实现。

java string 16进制-图3
(图片来源网络,侵删)
public class HexConverter {
    public static String bytesToHex(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(String.format("%02X", b & 0xFF));
        }
        return sb.toString();
    }
    public static void main(String[] args) {
        String originalString = "Hello";
        byte[] byteArray = originalString.getBytes();
        String hexString = bytesToHex(byteArray);
        System.out.println("Byte Array to Hex (Manual): " + hexString); // 输出: 48656C6C6F
    }
}

16进制字符串 → 字节数组 (推荐)

同样,使用 javax.xml.bind.DatatypeConverter 是最方便的。

方案 A: javax.xml.bind.DatatypeConverter (JDK 8及以下)

import javax.xml.bind.DatatypeConverter;
public class HexConverter {
    public static byte[] hexToBytes(String hexString) {
        if (hexString == null || hexString.isEmpty()) {
            return new byte[0];
        }
        // DatatypeConverter 提供了直接转换的方法
        return DatatypeConverter.parseHexBinary(hexString);
    }
    public static void main(String[] args) {
        String hexString = "48656C6C6F";
        byte[] byteArray = hexToBytes(hexString);
        // 将字节数组转换回字符串以验证
        String originalString = new String(byteArray);
        System.out.println("Hex to Byte Array: " + java.util.Arrays.toString(byteArray));
        System.out.println("Recovered String: " + originalString); // 输出: Hello
    }
}

方案 B: 手动循环 (理解原理)

public class HexConverter {
    public static byte[] hexToBytes(String hexString) {
        if (hexString == null || hexString.isEmpty()) {
            return new byte[0];
        }
        // 确保字符串长度是偶数
        if (hexString.length() % 2 != 0) {
            throw new IllegalArgumentException("Invalid hex string: " + hexString);
        }
        byte[] bytes = new byte[hexString.length() / 2];
        for (int i = 0; i < bytes.length; i++) {
            // 每次取两个字符
            String hexByte = hexString.substring(2 * i, 2 * i + 2);
            bytes[i] = (byte) Integer.parseInt(hexByte, 16);
        }
        return bytes;
    }
    public static void main(String[] args) {
        String hexString = "48656C6C6F";
        byte[] byteArray = hexToBytes(hexString);
        String originalString = new String(byteArray);
        System.out.println("Hex to Byte Array (Manual): " + java.util.Arrays.toString(byteArray));
        System.out.println("Recovered String: " + originalString); // 输出: Hello
    }
}

总结与最佳实践

转换方向 推荐方法 (JDK 8) 推荐方法 (JDK 6-7) 手动实现 (学习用)
字节数组 → 16进制字符串 DatatypeConverter.printHexBinary() DatatypeConverter.printHexBinary() 循环 + String.format("%02X", ...)
16进制字符串 → 字节数组 DatatypeConverter.parseHexBinary() DatatypeConverter.parseHexBinary() 循环 + Integer.parseInt(hexStr, 16)

重要提示:DatatypeConverter 的废弃

JDK 9 开始,javax.xml.bind 包被标记为废弃,因为它属于 Java EE,而 Java 正在将 Java EE 的功能移到 Jakarta EE 中。

  • 在 JDK 9+ 项目中,如果你使用模块系统,可能需要添加 --add-modules java.xml.bind 来启用它。
  • 长期来看,建议将项目迁移到更新的库,如 Apache Commons Codec,它提供了更稳定和独立的 API。

替代方案:Apache Commons Codec (强烈推荐)

这是一个非常流行且稳定的第三方库,专门用于各种编码和解码。

添加 Maven 依赖

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.15</version> <!-- 使用最新版本 -->
</dependency>

使用 Hex

import org.apache.commons.codec.binary.Hex;
public class CommonsHexExample {
    public static void main(String[] args) {
        String originalString = "Hello, Apache Commons!";
        byte[] byteArray = originalString.getBytes();
        // 1. 字节数组 -> 16进制字符串
        String hexString = Hex.encodeHexString(byteArray);
        System.out.println("Byte Array to Hex: " + hexString);
        // 输出: 48656C6C6F2C2041706163686520436F6D6D6F6E73
        // 2. 16进制字符串 -> 字节数组
        byte[] decodedBytes = Hex.decodeHex(hexString);
        // 验证
        String recoveredString = new String(decodedBytes);
        System.out.println("Recovered String: " + recoveredString);
        // 输出: Hello, Apache Commons!
    }
}

优点

  • API 简洁明了:encodeHexStringdecodeHex
  • 不依赖 Java EE 模块,兼容性好。
  • 广泛使用,社区支持好。

最终建议

  • 对于新项目:优先考虑使用 Apache Commons Codec,它更现代、更稳定,是行业标准之一。
  • 对于旧项目 (JDK 8):如果不想引入新依赖,javax.xml.bind.DatatypeConverter 是一个非常方便的选择。
  • 对于学习或面试:理解手动循环实现的过程非常重要,因为它能帮助你掌握底层原理,比如位运算和字符串格式化。
分享:
扫描分享到社交APP
上一篇
下一篇