Java編碼理解

來源:互聯網
上載者:User
Java編碼理解關鍵字:Java編碼,Unicode, getBytes()來源於我的筆記:有道筆記-Java編碼理解各類程式涉及的編碼不外乎這些: 原始碼檔案的編碼, 程式中字串的編碼, 程式執行輸出顯示時的編碼.Java號稱國際化的語言,是因為它的class檔案採用UTF-8,而JVM運行時使用UTF-16。摘自《談談對Java中Unicode、編碼的理解 http://blog.csdn.net/soleghost/article/details/959832 》在java程式的編譯和運行過程中都涉及了編碼轉換.

 1.  JAVAC是以系統預設編碼讀入源檔案,然後產生按UNICODE編碼的CLASS檔案。 摘自《Java GetBytes編碼方式 http://nopainnogain.iteye.com/blog/970628 》

      windows 系統預設編碼一般是 GBK,Linux 可以通過 LANG 來設定.

      可以通過指定編碼方式改變Javac讀入源檔案的編碼方式。

    javac -encoding GBK Test.java

      

      若一個來源程式檔案的編碼是 GBK, 並且程式中涉及中文字串,(手動輸入的中文字元的編碼方式就是當前檔案的編碼方式GBK. )

      

     此時,若 LANG=UTF-8,使用 javac Test3.java 編譯器時會出現如下警告:

     

     這是因為 javac 按照系統預設編碼 UTF-8 來讀取檔案, 遇到裡面的實為GBK中文字元無法在 UTF-8字元集中找到相應字元,所以出現警告。

     而使用 javac -encoding GBK Test3.java 則不會出現警告

 

2. 程式運行過程中調用getBytes(),new String(),println 列印字串顯示的過程中,都有編碼的轉換過程.

   Java 中的字串都是按 unicode 方式儲存的. 所有的編碼轉換均是從原始編碼轉化為 unicode,再由 unicode 轉換為 目標編碼的過程。

   如下程式:

   

  若 getBytes(),new String() 不指定相關編碼, 則它會按照系統預設編碼來處理

  例如 gbkStr.getBytes() 會按照系統預設編碼來返回位元組流, new String(bytes)會認為 bytes 位元組流是系統預設編碼。

  上述程式中的 gbkStr.getBytes().length 和 utfStr.getBytes().length 會在運行時由於 LANG 不同而出現不同的結果。

  LANG = zh_CN.GB18030,終端編碼為 GBK,運行結果為:

LANG = zh_CN.UTF-8,終端編碼為 UTF-8,運行結果為:

從運行結果看,我們有個疑問,為什麼第一個字串列印出來顯示都正常,而第二個字串卻顯示不正常呢。

我們看看這行代碼  new String(gbkStr.getBytes("GBK"), "UTF-8)

 

這句代碼可能我們會理解為將 GBK 的 String 轉化為 UTF-8 的String,這是大錯特錯的,實際上這行代碼有嚴重錯誤,直接導致 utfStr 裡儲存的不是能正常解碼的字元。

我們反覆講 JAVA中的String都是unicode編碼的,所以不存在GBK編碼的String”或“UTF8編碼的String”這樣的幼稚說法,上述程式的變數定義
gbkStr 和 utfStr 也是幼稚行為。

而這句話的實際含義是將gbkStr對象按照GBK的方式編碼為byte[],然後再把 byte[] 按照 UTF-8 的方式儲存到String中,(此句摘自《談談對Java中Unicode、編碼的理解 http://blog.csdn.net/soleghost/article/details/959832 》).

這句話涉及的實際操作是:gbkStr(Unicode字元)轉化為GBK字元,gbk字元轉化為 byte[] (即轉化結果存放到 bytes[] 中), 然後是 bytes[] 轉化為 UTF-8 字元, UTF-8 字元轉化為 unicode (即認為 byte[] 中是UTF-8字元的位元組碼,將byte[]轉化為 Unicode).

將一個 gbk 編碼的 byte[] 當作 utf8 方式儲存很明顯會出現錯誤,而正確代碼是這樣。由 gbkStr 對象得到 UTF-8 方式編碼的 byte[], 在按照 UTF-8 方式儲存到 utfStr.


LANG = zh_CN.GB18030,終端編碼為 GBK,運行結果為:


LANG = zh_CN.UTF-8,終端編碼為 UTF-8,運行結果為:

總結結果:

正確代碼

  不同環境下運行結果均是:28,36

 不同環境下運行結果均是:28,44

注意,

這裡由於原始碼檔案是 GBK 編碼, 所以  是GBK編碼,若檔案是UTF-8編碼,運行結果仍相同,結果與原始碼檔案中字元的編碼毫無關係,這是因為 在賦值給 gbkStr 時已經完成了到 unidoce
的轉化, gbkStr 中儲存的是統一的 unicode (gbkStr.length()得到的實際上是字串中unicode字元數量)。假若是從檔案中讀取字串而不是這裡這種直接語句賦值,則需要我們在讀取檔案時指定檔案的編碼格式才能得到正確的 String。而我們要得到某個編碼的輸出檔案時,只需在將 String 輸出到檔案時指定編碼格式就可以,非常方便。

因此:

要得到一個字串按照 UTF-8 編碼 和 GBK 編碼的位元組數組, 直接使用 string.getBytes(encoding) 就可以了,無需經過複雜的轉化。

上述程式在不同的 LANG和終端環境下均列印顯示正常,是因為在輸出到終端時有一個 unidoce ==> 其它編碼格式的轉化。

由此可看出,java中將字串使用 unidoce 統一編碼十分方便(Python也是這樣),而不像 C/C++ 中必須保證字串的編碼和LANG,終端環境一致才列印顯示正常。

建議在使用 getBytes 和 new String 時均指定編碼。

在上述代碼中, gbkStr 和 utfStr 中儲存的內容(unicode)是一樣的, 它們都對應著 28 個字元, 一個英文或中文均只算一個字元. 我們可以查看一下內容:

Unicode 值

此外,我們也可以看一下 gbk 位元組流 和 utf-8 位元組流的內容。

GBK 位元組流 (GBK中文字元按照兩個位元組編碼,英文按照一個位元組編碼)

UTF-8 位元組流(UTF-8中文字元編碼方式是變長的,這裡的幾個中文字元是按3個位元組編碼)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.