編碼體系速覽
| 編碼 | 類型 | 覆蓋範圍 | 字節長度 | 兼容性 |
| ISO-8859-1 | 單字節 | 西歐語言 | 1 | ASCII 超集 |
| GB2312/GBK | 雙字節 | 簡體/繁體中文 | 2 | 兼容 ISO-8859-1 |
| Unicode (UTF-16) | 定長雙字節 | 全字符集 | 2/4 | 不兼容其他 |
| UTF-8 | 變長 | 全字符集 | 1-4 | 兼容 ASCII |
「中文」二字編碼對照
字符: 中 文
Unicode: 4E2D 6587
UTF-8: E4 B8 AD E6 96 87
GBK: D6 D0 CE C4
ISO-8859-1: 無法表示 → 3F 3F (??)
Java 核心 API 互轉實戰
String → byte[] (getBytes)
String str = "中文";
byte[] utf8 = str.getBytes(StandardCharsets.UTF_8); // [E4, B8, AD, E6, 96, 87]
byte[] gbk = str.getBytes("GBK"); // [D6, D0, CE, C4]
byte[] iso = str.getBytes("ISO-8859-1"); // [3F, 3F] 丟失信息
byte[] → String (new String)
String restored = new String(utf8, StandardCharsets.UTF_8); // "中文" ✅
String restored = new String(gbk, "GBK"); // "中文" ✅
String restored = new String(iso, "ISO-8859-1"); // "??" ❌
完整可逆驗證
String original = "中文";
String roundTrip = new String(original.getBytes("UTF-8"), "UTF-8");
assert original.equals(roundTrip); // true
Web 層編碼設置(Servlet 規範)
請求解碼
// 必須在任何 getParameter() 之前調用
request.setCharacterEncoding("UTF-8");
響應編碼
// 方式 1: 設置 Content-Type
response.setContentType("text/html;charset=UTF-8");
// 方式 2: 設置字符編碼(需在 getWriter() 前)
response.setCharacterEncoding("UTF-8");
常見亂碼場景與修復
| 現象 | 原因 | 修復 |
| 中文變 ?? | ISO-8859-1 無法表示中文 | 全鏈路 UTF-8:DB、JDBC URL、JVM、Web 容器、前端頁面 |
| 中文變 | UTF-8 字節用 GBK 解碼 | 統一編碼為 UTF-8,或雙方協商 GBK |
| GET 參數亂碼 | Tomcat 8+ 默認 ISO-8859-1 解碼 URL | server.xml: <Connector URIEncoding="UTF-8"/> |
| POST 參數亂碼 | 未調用 request.setCharacterEncoding | Filter 第一行設置 UTF-8 |
JDBC 連接字符串編碼參數
// MySQL
jdbc:mysql://localhost:3306/db?characterEncoding=utf8&useUnicode=true
// PostgreSQL
jdbc:postgresql://localhost:5432/db?charSet=UTF-8
// Oracle (需 NLS_LANG 環境變量)
-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
總結
編碼鏈路「源頭→存儲→傳輸→展示」任一環節不一致即亂碼。黃金法則:全棧統一 UTF-8(數據庫、JDBC、JVM、容器、HTML、JS、CSS)。Java 內存固定 UTF-16,邊界轉換用 getBytes(charset)/new String(bytes, charset),Web 層用 Filter 鎖定 UTF-8,徹底告別亂碼。