Java字符串編碼原理以及亂碼解決方法

1 Java字符串編碼原理

??在Java中,字符的數(shù)據(jù)類型是char,而char類型的編碼是 Unicode 編碼,因此每一個char類型數(shù)據(jù)2字節(jié)16位,對應(yīng)在內(nèi)存中的數(shù)據(jù)就是字符的 Unicode 的碼值。而String類型的底層是一個char數(shù)組,因此String類型在內(nèi)存中的存儲形式是一系列字符對應(yīng)的 Unicode 碼值。


例如:中文字符串 "長風(fēng)幾萬里" ,表1是這5個中文字分別對應(yīng)的 GBK ,Unicode,和 UTF-8 編碼的碼值

表1:"長風(fēng)幾厘米"的碼表

字符 GBK Unicode UTF-8
B3A4 957F E995BF
風(fēng) B7E7 98CE E9A38E
BCB8 51E0 E587A0
CDF2 4E07 E4B887
C0EF 91CC E9878C

我們新建Main函數(shù)運行如下代碼:其中 Java 源文件的文件編碼格式為 UTF-8,Jvm 默認的字符集編碼格式也為 UTF-8 。

char[] cs = str.toCharArray();
System.out.println(Arrays.toString(Num2Hex.chars2HexStrings(cs)));
byte[] bUTF = str.getBytes("UTF-8");
System.out.println(Arrays.toString(Num2Hex.bytes2HexStrings(bUTF)));
byte[] bGBK = str.getBytes("GBK");
System.out.println(Arrays.toString(Num2Hex.bytes2HexStrings(bGBK)));

運行結(jié)果如下:

  [0x95, 0x7F, 0x98, 0xCE, 0x51, 0xE0, 0x4E, 0x07, 0x91, 0xCC]
  [0xE9, 0x95, 0xBF, 0xE9, 0xA3, 0x8E, 0xE5, 0x87, 0xA0, 0xE4, 0xB8, 0x87, 0xE9, 0x87, 0x8C]
  [0xB3, 0xA4, 0xB7, 0xE7, 0xBC, 0xB8, 0xCD, 0xF2, 0xC0, 0xEF]

如果我們把源文件的編碼格式改為GBK,運行結(jié)果不變


??也就是說對于String類型的字符串,他在內(nèi)存和 .class 文件中的編碼都是 Unicode 編碼,與源文件無關(guān),String類型的getBytes()方法,會將字符從 Unicode 編碼轉(zhuǎn)成參數(shù)指定名稱的字符集編碼的碼值(如果沒有指明字符集編碼,會按照 Jvm 的字符集編碼,如果沒有指定 Jvm 的字符集編碼,會根據(jù)操作系統(tǒng)的字符集編碼)然后返回這些碼值對應(yīng)的字節(jié)數(shù)組,由于 UTF-8 是3個字節(jié)表示一個漢字,所以返回的字節(jié)數(shù)組長度是15,而 GBK 編碼是2個字節(jié)表示一個漢字,所以返回的字節(jié)數(shù)組長度是10。

2 亂碼問題解決方法

??如何解決常見的亂碼問題呢?Java 字符編碼是 Unicode,字符集編碼我們最最常見的有 GBK,UTF-8,ISO-8859-1,解決亂碼的方法如下。
??首先搞清楚字符的數(shù)據(jù)源,例如"長風(fēng)幾萬里",如果字符數(shù)據(jù)源來自于String類型的常量,那么無論是在.class文件中還是在內(nèi)存中都是 Unicode 編碼,對應(yīng)的計算機數(shù)據(jù)用16進制表示就是{0x957F, 0x98CE, 0x51E0, 0x4E07, 0x91CC},如果是外部數(shù)據(jù)源,如果這5個字儲存在文件 a.txt 中并且 a.txt 的文件編碼假如是 GBK 的話,則文件 a.txt 存儲的計算機數(shù)據(jù)實際是這5個字符對應(yīng)的 GBK 的碼值,用16進制表示就是[0xB3, 0xA4, 0xB7, 0xE7, 0xBC, 0xB8, 0xCD, 0xF2, 0xC0, 0xEF],如果是 UTF-8 的話那么 a.txt 的內(nèi)容實際是[0xE9, 0x95, 0xBF, 0xE9, 0xA3, 0x8E, 0xE5, 0x87, 0xA0, 0xE4, 0xB8, 0x87, 0xE9, 0x87, 0x8C]。我們假設(shè) a.txt 編碼 是GBK,我們用 Java 讀取 a.txt 的文件內(nèi)容的字節(jié)保存在byte[]中,那么byte[]中的內(nèi)容還是這5個字符對應(yīng)的 GBK 的碼值[0xB3, 0xA4, 0xB7, 0xE7, 0xBC, 0xB8, 0xCD, 0xF2, 0xC0, 0xEF],如果我們讀取 a.txt 的文件內(nèi)容保存在char[]或者StringString的底層就是char[]String中的value就是保存在char[]中)中,那么我們就必須指明 a.txt 的字符集編碼,在字符集編碼正確的情況下,由于Java讀取外部數(shù)據(jù)源先獲得是數(shù)據(jù)源的字節(jié)流,因此 Java 還會將字節(jié)流轉(zhuǎn)為char[],就是要將[0xB3, 0xA4, 0xB7, 0xE7, 0xBC, 0xB8, 0xCD, 0xF2, 0xC0, 0xEF]轉(zhuǎn)成[0x957F, 0x98CE, 0x51E0, 0x4E07, 0x91CC],再保存在char[]String里,如果不能正確指明數(shù)據(jù)源的字符集編碼那么就會轉(zhuǎn)成亂碼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 編碼問題一直困擾著開發(fā)人員,尤其在 Java 中更加明顯,因為 Java 是跨平臺語言,不同平臺之間編碼之間的切換...
    x360閱讀 2,578評論 1 20
  • 字符是用戶可以讀寫的最小單位。計算機所能支持的字符組成的集合,就叫做字符集。字符集通常以二維表的形式存在。二維表的...
    劉惜有閱讀 8,367評論 2 14
  • 為什么要編碼 不知道大家有沒有想過一個問題,那就是為什么要編碼?我們能不能不編碼?要回答這個問題必須要回到計算機是...
    艾小天兒閱讀 17,874評論 0 2
  • 一群人能走到一起不容易,有的強勢,有的隨和,有的厲害,有的溫順,有的計較,有的大度,有的伶俐,有的深沉,有的鋒露,...
    回憶就想哭_d5af閱讀 166評論 0 0
  • 微信營銷 優(yōu)勢: 高到達率、高曝光率、髙接受率、高精準性、高便利性、 微信功能的商業(yè)價值 朋友圈:可以以幽默詼諧的...
    夢落星辰_ad4c閱讀 137評論 0 0

友情鏈接更多精彩內(nèi)容