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 不認識的字符都變成了“?”。