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

Java 字元編碼完全指南:GBK/UTF-8/Unicode/ISO-8859-1 轉換、Web 處理與避坑實戰

     編輯:Java 相關知識

編碼體系速查表

編碼類型字元範圍中文支援相容性
ISO-8859-1單位元組0-255無ASCII 超集,HTTP 預設
GB2312雙位元組6763 漢字簡體相容 ISO-8859-1 (英文)
GBK雙位元組21000+ 漢字簡繁體相容 GB2312、ISO-8859-1
Unicode (UTF-16)定長雙位元組所有字元全支援不相容 ISO-8859-1
UTF-8變長 1-4 位元組所有字元全支援相容 ASCII (0-127)

「中文」二字編碼實例

字元: 中  文
GBK:      D6 D0  CE C4
Unicode:  4E 2D  65 87
UTF-8:    E4 B8 AD  E6 96 87
ISO-8859-1: 無法表示 (若強制按位元組解讀: D6 D0 CE C4 → 4 個亂碼字元)

Java 核心 API 轉換

String.getBytes(charset) : String → byte[]

String s = "中文";
// 正確編碼
byte[] gbk = s.getBytes("GBK");      // [D6, D0, CE, C4]
byte[] utf8 = s.getBytes("UTF-8");   // [E4, B8, AD, E6, 96, 87]
// 錯誤編碼
byte[] iso = s.getBytes("ISO-8859-1"); // [3F, 3F] 兩個 '?' (0x3F)

new String(bytes, charset) : byte[] → String

// 正確解碼 (可逆)
String s1 = new String(gbk, "GBK");    // "中文" ✓
String s2 = new String(utf8, "UTF-8"); // "中文" ✓

// 錯誤解碼 (不可逆)
String s3 = new String(iso, "ISO-8859-1"); // "??" ✗
String s4 = new String(gbk, "UTF-8");      // 亂碼 ✗

完全可逆原則

// UTF-8 可表示所有字元,故完全可逆
String original = "中文English123";
String roundtrip = new String(original.getBytes("UTF-8"), "UTF-8");
assert original.equals(roundtrip); // 永真

Web 應用編碼處理鏈路

表單提交流程

用戶輸入(GBK) → 瀏覽器編碼(GBK) → HTTP 請求位元組流 
    → Tomcat 預設 ISO-8859-1 解碼 → getParameter() 亂碼
    → request.setCharacterEncoding("GBK") → 正確解碼

關鍵設定點總表

層級設定方式作用優先級
JSP 編譯<%@ page pageEncoding="GBK" %>原始檔讀取編碼高
JSP 輸出<%@ page contentType="text/html;charset=GBK" %>回應編碼 + 告知瀏覽器高
Servlet 請求request.setCharacterEncoding("UTF-8")POST 參數解碼 (需在 getParameter 前)高
Servlet 回應response.setCharacterEncoding("UTF-8")輸出編碼 + Content-Type高
HTML Meta<meta charset="UTF-8">靜態頁面告知瀏覽器中
表單屬性<form accept-charset="UTF-8">提交編碼 (瀏覽器支援度不一)低
Tomcat 全域<Connector URIEncoding="UTF-8" />GET 參數解碼 (全域生效)中
資料庫連線useUnicode=true&characterEncoding=UTF-8JDBC 連線編碼高

Filter 統一編碼 (推薦)

@WebFilter("/*")
public class EncodingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        chain.doFilter(req, resp);
    }
}

URL 編碼地獄與解決方案

問題根源

  • IE「總是使用 UTF-8 發送 URL」選項影響編碼
  • GET 參數在 URL 中,request.setCharacterEncoding() 無效
  • Tomcat 預設 ISO-8859-1 解碼 URL

UTF-8 判斷算法

public static boolean isValidUtf8(byte[] bytes) {
    int i = 0;
    while (i < bytes.length) {
        byte b = bytes[i++];
        if (b >= 0) continue; // ASCII
        if (b < (byte)0xC0 || b > (byte)0xFD) return false;
        int count = (b > (byte)0xFC) ? 5 : (b > (byte)0xF8) ? 4 
                    : (b > (byte)0xF0) ? 3 : (b > (byte)0xE0) ? 2 : 1;
        if (i + count > bytes.length) return false;
        for (int j = 0; j < count; j++) {
            if (bytes[i++] < (byte)0x80) return false; // 續位元組必須 10xxxxxx
        }
    }
    return true;
}

// 使用
String param = new String(bytes, isValidUtf8(bytes) ? "UTF-8" : "GBK");

缺陷

  • 誤判:GBK 「學習」 (D1 A7 CF B0) 符合 UTF-8 格式 → 誤判為 UTF-8
  • Google 同樣遇此問題,無完美方案

資料庫與系統層編碼

MySQL

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

# 連線 URL
jdbc:mysql://host/db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

Linux 環境變數

export LANG=zh_CN.UTF-8
export LC_ALL=zh_CN.UTF-8
# 影響 JVM 預設編碼、URLEncoder、檔案系統

檔案系統掛載

# NTFS 支援中文檔名
mount -t ntfs -o iocharset=gb2312 /dev/sda1 /mnt/data

常見亂碼場景診斷表

現象可能原因解決
??? 或 編碼不支援字元 (如 ISO-8859-1 存中文)全鏈路 UTF-8
鍟斤拷UTF-8 被 GBK 解碼統一 UTF-8
涓婁竴GBK 被 UTF-8 解碼統一 GBK 或轉 UTF-8
中文變成 ??ISO-8859-1 強制編碼設定正確編碼
檔案開頭 3 個不可見字元UTF-8 BOM (EF BB BF)用無 BOM 編碼儲存

總結:編碼統一鐵律

  1. 全棧 UTF-8:原始碼、資料庫、JVM、Tomcat、瀏覽器、檔案系統
  2. 原始檔無 BOM:IDE 設定 UTF-8 without BOM
  3. Filter 統一請求/回應編碼
  4. 資料庫用 utf8mb4:支援 Emoji/生僻字
  5. GET 參數慎用,優先 POST + JSON
  6. URL 編碼指定 UTF-8:URLEncoder.encode(s, "UTF-8")

編碼問題本質是發送端與接收端約定不一致。建立團隊編碼規範、CI 檢查原始檔編碼、統一基礎設施配置,比事後除錯高效百倍。

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