1 byte = 8 位 = 2 個十六進制字符 (4 位/字符)
byte 值:123 (0x7B)
二進制:0111 1011
高 4 位:0111 (7) → 字符 '7'
低 4 位:1011 (B) → 字符 'B'
結果:"7B"
public class HexUtil {
private static final char[] HEX_DIGITS =
{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/** byte[] → 十六進制字符串 */
public static String bytesToHex(byte[] src) {
if (src == null || src.length == 0) return "";
char[] res = new char[src.length * 2];
for (int i = 0, j = 0; i < src.length; i++) {
res[j++] = HEX_DIGITS[(src[i] >>> 4) & 0x0F]; // 高 4 位 (無符號右移)
res[j++] = HEX_DIGITS[src[i] & 0x0F]; // 低 4 位
}
return new String(res);
}
/** 十六進制字符串 → byte[] */
public static byte[] hexToBytes(String hex) {
if (hex == null || hex.isEmpty() || (hex.length() & 1) != 0) return null;
byte[] bytes = new byte[hex.length() / 2];
for (int i = 0; i < bytes.length; i++) {
int high = Character.digit(hex.charAt(i * 2), 16);
int low = Character.digit(hex.charAt(i * 2 + 1), 16);
if (high == -1 || low == -1) return null; // 非法字符
bytes[i] = (byte) ((high << 4) | low);
}
return bytes;
}
}
// byte[] → Hex
public static String toHexBigInteger(byte[] bytes) {
return new BigInteger(1, bytes).toString(16); // 注意:會丟失前導零
}
// Hex → byte[]
public static byte[] fromHexBigInteger(String hex) {
return new BigInteger(hex, 16).toByteArray(); // 可能產生額外符號位
}
import java.util.HexFormat;
public class ModernHexUtil {
private static final HexFormat FORMAT = HexFormat.of().withUpperCase();
public static String toHex(byte[] bytes) {
return FORMAT.formatHex(bytes);
}
public static byte[] fromHex(String hex) {
return FORMAT.parseHex(hex);
}
}
public static String getFileMD5(File file) throws IOException {
try (FileInputStream fis = new FileInputStream(file);
DigestInputStream dis = new DigestInputStream(fis, MessageDigest.getInstance("MD5"))) {
// 必須讀完流才能觸發摘要計算
byte[] buffer = new byte[8192];
while (dis.read(buffer) != -1) { /* 讀取觸發更新 */ }
return HexUtil.bytesToHex(dis.getMessageDigest().digest());
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 算法不可用", e);
}
}
| 方法 | 耗時 (ms) | 相對性能 |
|---|---|---|
| 查表法 (方案一) | ~120 | 1.0x (基準) |
| HexFormat (Java 17+) | ~150 | 1.25x |
| String.format("%02x") | ~850 | 7x |
| BigInteger | ~2100 | 17x |
byte b = -1; b & 0xFF 得到 255,必須配合 & 0xFF 消除符號位new BigInteger(1, bytes).toString(16) 會丟失高位零,需手動補齊hex.length() % 2 == 0字符串與 byte[] 互轉本質是二進制與十六進制文本表示的轉換。生產環境推薦:Java 17+ 使用 HexFormat,舊版本使用查表法 (方案一),兼顧性能與零依賴。避免使用 String.format/BigInteger 等高開銷方案。