java的編碼問題詳解


ucenter的中文問題終於解決,這也暴露我對Java編碼知識的嚴重不足,經過多次試驗和搜索,對這塊知識終於有了一個新的認識,所以把理解的內容寫道這里

1:JVM的內存中字符串的編碼格式是統一的嗎?

JVM里面的任何字符串資源都是Unicode,String相當於 char[] 。 而JVM中的byte[]是帶編碼的,比如,Big5,GBK,GB2312,UTF-8之類的。一個GBK編碼的byte[] 轉換成 String,

其實就是從GBK編碼向Unicode編碼轉換。一個String轉換成一個Big5編碼的byte[],其實就是從Unicode編碼向Big5編碼轉換。所以,Unicode是所有編碼轉換的中間介質。所有的編碼都有一個轉換器可以轉換到Unicode,而Unicode也可以轉換到其他所有的編碼。

這個做個測試

public class CodeTest {

    @Test
    public void test() throws UnsupportedEncodingException {
        String str="I am 高興";
        System.out.println(str);
    }
}

在debug中顯示'高'的值我39640,為該中文字符的unicode的編碼,Java中的char是2個字節的。 

2:源文件的編碼對編譯的影響。

這里我專門使用了Javac和Java兩個命令來做個這個試驗,源碼如下:

public class CodeTest
{
public static void main (String[] args)
{
String str="高興";
System.out.println(str);
}
}

這個源碼我在UE里面把他轉成GBK的,編譯沒有問題。但是轉成UTF-8格式,就出現了問題:”楂樺叴“ ,

public class CodeTest {

    @Test
    public void test() throws UnsupportedEncodingException {
//        String str="I am 君山";
//        System.out.println(str);
        String str="高興";
        str=new String(str.getBytes("UTF-8"),"GBK");
        System.out.println(str);
    }
}

str的值為”楂樺叴“。說明源文件的編碼對編譯時有影響的。GBK為本地系統的編碼。Javac在編譯過程中把UTF-8的轉成了GBK.  下面一段是解釋:

 Java編譯器在對源文件編譯前,首先會源文件轉換為unicode編碼,然后再進行編譯。例如:我們的源文件是以UTF-8的方式保存的,而在編譯時編譯器卻把它當作是用GBK方式保存的,這樣編譯器就會按照GBK->Unicode的編碼轉換方法對源文件進行轉換,然后再編譯,這樣當然會出錯,實際上編譯器應當按照UTF-8->Unicode的編碼轉換方法來對源文件進行轉換。 

常我們手動建立一個java文件Demo.java,並保存。此時Demo.java文件的編碼為ANSI,中文操作系統下就是GBK.然后使用javac命令來編譯該源文件。”javac Demo.java”。Javac也需要讀取java文件,那么javac是使用什么編碼來解碼我們讀取的字節呢?其實javac采用了操作系統默認的GBK編碼解碼我們讀取的字節,這個編碼正好也是Demo.java文件的編碼,二者一致,所以不會出現亂碼情況。讓我們來做點手腳,在保存Demo.java文件時,我們選擇UTF-8保存。此時Demo.java文件編碼就是UTF-8了。我們再使用”javac Demo.java”來編譯,如果Demo.java里含有中文字符,此時控制台會出現警告信息,也出現了亂碼。究其原因,就是因為javac采用了GBK編碼解碼我們讀取的字節。因為我們的字節是UTF-8編碼的,所以會出現亂碼。如果不信的話你可以自己試試。那么解決辦法呢?解決辦法就是使用javac的encoding參數來制定我們的解碼編碼。如下:javac -encoding UTF-8 Demo.java。這里我們指定了使用UTF-8來解碼讀取的字節,由於這個編碼和Demo.java文件編碼一致,所以不會出現亂碼情況了。

3:String的編碼和解碼

String對象的getBytes()可以對字符串進行編碼轉化成byte數組。

 public static void encode() {  
        String name = "I am 君山"; 
        toHex(name.toCharArray()); 
        try { 
            byte[] iso8859 = name.getBytes("ISO-8859-1"); 
            toHex(iso8859); 
            byte[] gb2312 = name.getBytes("GB2312"); 
            toHex(gb2312); 
            byte[] gbk = name.getBytes("GBK"); 
            toHex(gbk); 
            byte[] utf16 = name.getBytes("UTF-16"); 
            toHex(utf16); 
            byte[] utf8 = name.getBytes("UTF-8"); 
            toHex(utf8); 
        } catch (UnsupportedEncodingException e) { 
            e.printStackTrace(); 
        } 
 }

默認使用系統編碼。

String(byte[],charset)這是對字節數組進行解碼。這個是經常容易出問題的地方,你使用gbk編碼,卻使用utf-8解碼,那么生成的String的unicode的編碼已經變了。字節數組通過編碼映射到指定的字符,然后這些字符轉成unicode編碼轉成

解碼的黑洞問題:

將中文和中文符號經過不支持中文的 ISO-8859-1 編碼后,所有字符變成了“?”,這是因為用 ISO-8859-1 進行編解碼時遇到不在碼值范圍內的字符時統一用 3f 表示,這也就是通常所說的“黑洞”,所有 ISO-8859-1 不認識的字符都變成了“?”。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM