String a = "你好";
// getBytes輸出
a.getBytes("UTF-8"); // [-28, -67, -96, -27, -91, -67]
// URLEncoder輸出
URLEncoder.encode(a, "UTF-8"); // %E4%BD%A0%E5%A5%BD
同樣UTF-8編碼,為何字節表現截然不同?
| 維度 | getBytes( charset ) | URLEncoder.encode( charset ) |
|---|---|---|
| 本質操作 | 字符 → 字節序列(編碼) | 字符 → 字節序列 → %XX 形式(編碼+URL逃逸) |
| 輸出類型 | byte[](原始字節) | String(ASCII可打印字符) |
| 處理非ASCII | 直接輸出字節值(有符號byte顯示負數) | 每字節轉為 %XX 十六進制大寫 |
| 處理空格 | 編碼為 0x20 | 轉為 + 號(application/x-www-form-urlencoded規範) |
| 適用場景 | 文件存儲、網絡傳輸、加密輸入 | URL查詢參數、表單提交、HTTP Body |
「你好」UTF-8編碼為6字節:
你 → E4 BD A0
好 → E5 A5 BD
getBytes:直接返回{0xE4, 0xBD, 0xA0, 0xE5, 0xA5, 0xBD},Java有符號byte顯示為負數URLEncoder:將每字節格式化為%E4%BD%A0%E5%A5%BDString s = "你好";
byte[] raw = s.getBytes(StandardCharsets.UTF_8);
StringBuilder hex = new StringBuilder();
for (byte b : raw) {
hex.append(String.format("%02X ", b & 0xFF)); // 無符號十六進制
}
System.out.println("原始字節: " + hex); // E4 BD A0 E5 A5 BD
String encoded = URLEncoder.encode(s, StandardCharsets.UTF_8.name());
System.out.println("URL編碼: " + encoded); // %E4%BD%A0%E5%A5%BD
// 反向驗證
String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8.name());
System.out.println("解碼還原: " + decoded); // 你好
原答案提到「UTF-8中文3字節,GB2312中文2字節」雖然正確,但未說明URLEncoder在字節基礎上又做了一層%XX轉換,這才是輸出差異的直接原因。
getBytes + Base64URLEncoder.encodeURLEncoder.encode(或框架自動處理)getBytesgetBytes是純編碼,URLEncoder.encode是編碼+URL逃逸。兩者服務於完全不同的協議層,不可互換。理解「字節→%XX」這一額外轉換步驟,是區分二者的關鍵。