java字符串編碼認識誤區說明


本文章由@唐乾 出品,轉載請註明出處。  
文章鏈接: http://blog.csdn.net/tang9140/article/details/40978369

 

最近深入研究了java內部字符串編碼方式,發現大家在對java字符串編碼認識上存在很大的分歧。網上的說法很多,其中很多都是不嚴謹的說法或者說是錯誤的說法。現在把常見認識誤區列舉如下:

 

誤區一:java的字符串是unicode編碼,java編碼方式是unicode,java內字符編碼是unicode

 

說明:上面的說法都提到unicode編碼,這是非常不正確的說法。首先說下什麼是unicode。以下摘自百度百科


Unicode是國際組織制定的可以容納世界上所有文字和符號的字符編碼方案。Unicode用數字0-0x10FFFF來映射這些字符,最多可以容納1114112個字符,或者說有1114112個碼位。碼位就是可以分配給字符的數字。UTF-8、UTF-16、UTF-32都是將數字轉換到程序數據的編碼方案。


簡單說unicode只是規定了每個字符對應的數字,即碼位,只是作字符集(charset)用,而不是程序編碼(encoding)。unicode是字符集,而utf-8,utf-16纔是具體的編碼方式,兩者千萬不能搞混了。


我假設java是unicode編碼,那豈不是意味着每個字符至少要用3個字節(因最大數字0x10FFFF佔用三個字節)來表示,這顯示是不對的。

衆所周知,java中的String類型實際是char數組構成的,一個char佔用兩個字節。


那爲什麼一個char佔用兩個字節?因爲String實際採用UTF-16 編碼方式存儲所有字符。UTF-16規定用兩個字節或四個字節來唯一表示unicode字符,因此java約定一個基本char類型佔用兩個字節,這樣通過一個char或兩個char就能唯一表示unicode字符。

綜上所述,可以說java字符串採用的字符集是unicode,而編碼方式是utf-16。


 

誤區二:java中一個漢字用一個char就能表示

 


說明:根據上面所述,String採用UTF-16編碼方式來存儲字符,因此對於基本平面(BMP或平面0)的字符用一個char就能表示,但是對於其它平面的字符則需要兩個char才能表示。簡單說就是對於unicode的0-0xFFFF範圍的字符用一個char就能表示,但是0x10000-0x10FFFF範圍的字符就要用兩個char才能表示。


那麼就存在一個問題,java對內存中的兩個連續的char,它怎麼知道是一個char對應一個字符,還是這兩個連續的char構成一個字符。這就涉及到unicode的特殊約定和utf-16編碼的具體實現了。詳細如下:

1、unicode約定平面0的0xD800-0xDFFF,共2048個碼位,是一個被稱作代理區(Surrogate)的特殊區域。代理區的目的用兩個UTF-16字符表示BMP以外的字符。

2、UTF-16編碼以16位無符號整數爲單位。我們把Unicode編碼記作U。編碼規則如下:

  • 如果U<0x10000,U的UTF-16編碼就是U對應的16位無符號整數(爲書寫簡便,下文將16位無符號整數記作WORD)。
  • 如果U≥0x10000,我們先計算U'=U-0x10000,然後將U'寫成二進制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16編碼(二進制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。這樣當程序遇到第一個char在D800-DBFF或DC00-DFFF範圍時,就知道這個char是需要跟後面的char合併來對應一個字符。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章