Java 的字串

文章推薦指數: 80 %
投票人數:10人

任何一本Java 入門的書都會談到,Java 的字串使用Unicode,那麼是否想過,明明你的文字編輯器是使用MS950 編碼,為什麼會寫下的字串在JVM 中會是Unicode?如果在一個. 回Encoding目錄 任何一本Java入門的書都會談到,Java的字串使用Unicode,那麼是否想過,明明你的文字編輯器是使用MS950編碼,為什麼會寫下的字串在JVM中會是Unicode?如果在一個Main.java中寫下以下的程式碼並編譯: publicclassMain{ publicstaticvoidmain(String[]args){ System.out.println("Test"); System.out.println("測試"); } } 如果作業系統預設編碼是MS950,而文字編輯器是使用MS950編碼,那麼你如下執行編譯: C:\workspace>javacMain.java 產生的.class檔案,使用任何的反組譯工具還原回來的程式碼中,你可能會看到以下的內容: importjava.io.PrintStream; publicclassMain{ publicMain(){} publicstaticvoidmain(Stringargs[]){ System.out.println("Test"); System.out.println("\u6E2C\u8A66"); } } 其中"\u6E2C\u8A66"就是"測試"的Unicode碼點表示,JVM在載入.class之後,就是讀取Unicode編碼並產生對應的字串物件,而不是最初在原始碼中寫下的"測試"。

那麼編譯器怎麼知道要將中文字元轉為哪個Unicode編碼?正如〈你的原始碼是什麼編碼?〉談過的,當使用javac指令沒有指定-encoding選項時,會使用作業系統預設編碼,如果文字編譯器是使用UTF-8編碼,那麼編譯時就要指定-encoding為UTF-8,如此編譯器才會知道用何種編譯讀取.java的內容。

例如: C:\workspace>javac-encodingUTF-8Main.java 那麼啟動JVM之後,字串的實作位元組呢?如果想取得字串的位元組資料,可以使用String的getBytes()方法。

例如: packagecc.openhome; importstaticjava.lang.System.out; publicclassMain{ publicstaticvoidmain(String[]args)throwsException{ print("UTF-16","測試".getBytes("UTF-16")); print("UTF-8","測試".getBytes("UTF-8")); print("Big5","測試".getBytes("Big5")); print("default","測試".getBytes()); } privatestaticvoidprint(Stringencoding,byte[]bytes){ out.printf("%s\t",encoding); for(byteb:bytes){ out.printf("%-3h",b&0x00FF); } out.println(); } } getBytes()在使用時,可以指定用哪個編碼取得字串的位元組序列,上面這個程式,分別將「測試」以UTF-16、UTF-8、Big5三種編碼取得位元組序列,結果如下,可以用十六進位編輯器來印證「測試」在這幾種編碼下,位元組序列是不是與執行結果相同(注意純文字中UTF-16開頭若是fe、ff,那是BOM): UTF-16feff6e2c8a66 UTF-8e6b8ace8a9a6 Big5b4fab8d5 defaultb4fab8d5 getBytes()可以不指定編碼呼叫,此時會用〈JVM預設編碼〉,在啟動JVM沒有任何指定的情況下,就會與作業系統預設編碼一致,上面的執行結果是在正體中文Windows下執行的,所以getBytes()預設就會使用Big5來取得位元組序列。

如果有一個位元組陣列,可以用來建構字串,建構時可指定以何種編碼方式來解釋所提供的位元組陣列。

例如: packagecc.openhome; importstaticjava.lang.System.out; publicclassMain{ publicstaticvoidmain(String[]args)throwsException{ out.println(newString(toBytes(0xfe,0xff,0x6e,0x2c,0x8a,0x66),"UTF-16")); out.println(newString(toBytes(0xe6,0xb8,0xac,0xe8,0xa9,0xa6),"UTF-8")); out.println(newString(toBytes(0xb4,0xfa,0xb8,0xd5),"Big5")); out.println(newString(toBytes(0xb4,0xfa,0xb8,0xd5))); } privatestaticbyte[]toBytes(int...ints){ byte[]bytes=newbyte[ints.length]; for(inti=0;i{ try{ //當初是哪個位元組陣列被解釋為UTF-8的?逐一嘗試! byte[]bytes="®õ¤s½Y¥Û±Ð·|".getBytes(charset); out.printf("%s%s%n",charset,newString(bytes,"Big5")); }catch(Exceptione){ //nope } }); } } 編譯與執行後,嘗試從結果中看到可辨識的文字: C:\workspace>javac-encodingUTF-8Main.java C:\workspace>javaMain 略... ISO-8859-1泰山磐石教會 ISO-8859-13泰山磐???會 略... windows-1252泰山磐石教會 windows-1253?山磐??會 windows-1254泰山磐石?會 略... 當使用ISO-8859-1或windows-1252嘗試取回的位元組陣列,可用Big5編碼解釋來建立可辨識的字串結果。

如果這是資料庫的某個欄位,現在可以直接撰寫程式取得其它欄位字串結果,使用ISO-8859-1(或windows-1252,不過這比較不可能)取得位元組陣列,再用以建立Big5字串,看看結果是否都是可辨識的,如果確認是的話,就可以重新將這些欄位用正確的編碼寫回資料庫。

PS.上面這個範例來自JWorld@TW的討論文章。



請為這篇文章評分?