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

Java String 核心機制深度解析:內部結構、substring 實現與編碼陷阱

     編輯:Java 程式設計入門

String 類的內部結構

在 Java 中,String 類被聲明為 final,其核心字段包括:

  • private final char value[]:存儲字符數組
  • private final int offset:起始位置偏移量
  • private final int count:字符實際長度
  • private int hash:緩存的哈希值(默認為 0,調用 hashCode() 後計算)

這種設計使得 String 實例在創建後不可變,所有修改操作都會返回新對象。

substring 的零拷貝實現原理

早期 JDK 版本(JDK 7u6 之前)的 substring 採用共享字符數組策略:

public String substring(int beginIndex, int endIndex) {
    // 邊界檢查省略...
    return ((beginIndex == 0) && (endIndex == count)) ? this :
        new String(offset + beginIndex, endIndex - beginIndex, value);
}

String(int offset, int count, char value[]) {
    this.value = value;
    this.offset = offset;
    this.count = count;
}

優點:O(1) 時間複雜度,節省內存。缺點:若原字符串極大而子串很小,會導致原數組無法被 GC 回收,造成內存洩漏。JDK 7u6 後改為複製數組方式。

JVM 默認字符編碼機制

JVM 啟動時通過 Charset.defaultCharset() 確定默認編碼,邏輯如下:

  1. 讀取系統屬性 file.encoding(可通過 -Dfile.encoding=utf-8 指定)
  2. 查找對應的 Charset 實現
  3. 若失敗則回退到 UTF-8

可通過 System.getProperty("file.encoding") 查看當前值。

字節編解碼核心流程

String.getBytes(charset) 最终委託給 CharsetEncoder.encode(),核心邏輯在 encodeLoop() 中將字符緩衝區轉換為字節緩衝區。該方法支持流式處理(nio 包特性),雖然單次調用通常不會循環。

經典亂碼場景與根因分析

以下代碼演示了編碼不一致導致的數據損壞:

String str = "字符串";
// 默認編碼(如GBK)獲取字節
printArray(str.getBytes());        // -41 -42 -73 -5 -76 -82 (6字節)
// 顯式指定UTF-8
printArray(str.getBytes("utf-8")); // -27 -83 -105 -25 -84 -90 -28 -72 -78 (9字節)

// 錯誤示範:GBK字節按UTF-8解碼
System.out.println(new String(str.getBytes(), "utf-8"));        // ???
System.out.println(new String(str.getBytes("utf-8"), "gbk"));   // 字符??
// 看似恢復實則數據已損壞
System.out.println(new String("瀛楃涓?".getBytes("gbk"), "utf-8")); // 字符??

核心原因:GBK 雙字節編碼漢字,UTF-8 三字節編碼漢字。編解碼編碼不匹配會導致字節序列被錯誤解析,產生替換字符(如 0x3F '?')。雖然表面可通過「雙重轉換」恢復純漢字串,但要求漢字數量為偶數,實際不可靠。

工程級解決方案

方案一:URL 編碼傳輸

利用 GBK/UTF-8 對 ASCII 字符(字母、數字、%)編碼一致的特性:

// 前端
String encoded = URLEncoder.encode(originalStr, "UTF-8");
// 後端
String decoded = URLDecoder.decode(receivedStr, "UTF-8");

確保傳輸層面字節序列不變,徹底規避編碼不匹配。

方案二:全鏈路統一編碼

在 Web 框架配置中強制指定編碼,例如 WebX:

<webx defaultCharset="UTF-8">...</webx>

同時設置 Tomcat URIEncoding="UTF-8"、數據庫連接字符集、頁面 <meta charset="UTF-8">,實現端到端一致性。

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