天天看點

java編碼詳解舉個例子java編譯到輸出例子解析

我們在開發過程中,特别是多種編碼格式并存的情況下,很容易遇到亂碼問題。 假如有一個GBK編碼java檔案,然後再使用-Dfile.encoding=GBK參數,寫入的檔案中哪些是亂碼呢。那如果使用UFT-8編碼的java檔案呢。

<a href="http://blog.51cto.com/13013670/1944050#">?</a>

<code>public</code> <code>class</code> <code>Main {</code>

<code>    </code><code>static</code> <code>String content = </code><code>"中文"</code><code>;</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) </code><code>throws</code> <code>IOException {</code>

<code>        </code><code>OutputStreamWriter gbkWriter =</code><code>new</code> <code>OutputStreamWriter(</code><code>new</code> <code>FileOutputStream(</code><code>"GBK-FILE"</code><code>),</code><code>"GBK"</code><code>);</code>

<code>       </code><code>// 情況1、2、5的結果肯定是一緻的</code>

<code>        </code><code>gbkWriter.write(content+</code><code>"\n"</code><code>); </code><code>//(1)</code>

<code>        </code><code>gbkWriter.write(</code><code>new</code> <code>String(content.getBytes(</code><code>"GBK"</code><code>),</code><code>"GBK"</code><code>)+</code><code>"\n"</code><code>);             </code><code>// (2)</code>

<code>        </code><code>gbkWriter.write(</code><code>new</code> <code>String(content.getBytes(</code><code>"GBK"</code><code>), </code><code>"UTF-8"</code><code>)+</code><code>"\n"</code><code>);          </code><code>// (3)</code>

<code>        </code><code>gbkWriter.write(</code><code>new</code> <code>String(content.getBytes(</code><code>"UTF-8"</code><code>),</code><code>"GBK"</code><code>)+</code><code>"\n"</code><code>);            </code><code>// (4)</code>

<code>        </code><code>gbkWriter.write(</code><code>new</code> <code>String(content.getBytes(</code><code>"UTF-8"</code><code>), </code><code>"UTF-8"</code><code>)+</code><code>"\n"</code><code>);   </code><code>// (5)</code>

<code>        </code><code>gbkWriter.flush();</code>

<code>        </code><code>gbkWriter.close();</code>

<code>    </code><code>}</code>

<code>}</code>

  

其實用一張圖就可以清晰的概括出從java檔案編譯到輸出的過程  主要有3個地方的編碼轉換:

上圖①所示的位置,其實就是

javac -encoding xxx

的時候控制,如果你沒有顯示的指定編碼,那麼會根據目前作業系統的預設編碼格式進行編譯,一般windows是gbk,linux是UTF-8。如果這裡編碼指定錯了,那麼你的代碼很有可能出現中文亂碼問題,注意是很有可能,而不是絕對。原因後面會說到。編譯出來的class檔案統一都是UTF-8格式

當class檔案加載的jvm的時候,也會進行字元串編碼轉換,和前面一樣,會使用作業系統預設的編碼格式,這裡的編碼不是指class檔案的編碼,而是指java檔案的編碼格式,類似于指定java檔案是什麼編碼格式編譯為class檔案的。就是jvm參數:

java -Dfile.encoding=xxx

在java運作過程中,字元串在記憶體中則是使用Unicode(UTF-16)進行存儲的。而UTF-8轉換為UTF-16是很簡單的過程。當我們标用String.getBytes()時候,則是把記憶體中的unicode轉換對應的位元組數組。(如果沒有指定,則使用作業系統預設的編碼格式)。可以看出,把一個字元串從編譯到記憶體,其實是經曆的過程為:

編譯檔案編碼-&gt;加載jvm編碼-&gt;unicode

輸出的編碼則是在代碼中指定的。例如: OutputStreamWriter gbkWriter =new OutputStreamWriter(new FileOutputStream("GBK-FILE"),"GBK");

如果了解上面的,我們再看看文章一開始的例子。舉幾個例子做說明,其他的情況也就逐類旁通。

java檔案編碼:GBK,

javac -encoding GBK

java -Dfile.encoding=GBK 那麼使用GBK編碼檢視輸出檔案

(1)正常

(2)正常

(3)亂碼

(4)亂碼

(5)正常

情況1是比較好了解的,因為java檔案編碼、編譯、加載都是使用GBK,加載到記憶體中Unicode肯定也是正常的,那麼列印出來也是正常的。

在情況1的前提下(即加載到記憶體中是正常的),在jvm中使用GBK解碼在編碼肯定是正常的。

在情況1的前提下,使用不同的解碼和編碼,肯定是亂碼

當我們使用UTF-8的格式打開檔案的時候,情況(4)是正常的,其餘都是亂碼。其實是因為先使用unicode進行轉換為UTF-8格式的Byte數組,生成的字元串雖然亂碼和寫檔案的格式都是GBK,相當于原封不動的UTF-8格式的byte數組寫到檔案中,是以就會出現這個情況

這個例子就是直至加載到記憶體都是正常的情況下,在jvm内進行編碼和解碼導緻亂碼的情況

java檔案編碼:UTF-8,

java -Dfile.encoding=UTF-8

(1)亂碼

(2)亂碼

(3)正常

(5)亂碼

情況1是亂碼,說明字元串加載到記憶體中就已經是亂碼了。因為UFT-8格式使用GBK進行編碼,在生成class檔案就已經是亂碼了。

情況3為什麼又是正常的呢,其實這是誤打誤撞類型。個人了解的造成這個情況的原因有:

java檔案的編碼正好和jvm加載檔案編碼格式是一樣的

javac過程,相當于一個UTF-8-&gt;GBK格式轉換,而content.getBytes("GBK"), "UTF-8")又相當于GBK-&gt;UTF-8的轉換,兩次轉換正好互相抵消。

為什麼是使用UTF-8打開情況1不是亂碼了呢,其實和上面誤打誤撞,隻不過之前發生在記憶體中的GBK-&gt;UTF-8換為我們在打開檔案的時候進行的編碼轉換,情況1、2、5結果肯定一緻的

本文轉自 bxst 51CTO部落格,原文連結:http://blog.51cto.com/13013670/1944050