JAVA裏字符編碼的探索與理解

  今天終於把JAVA裏一個比較頭痛的問題——字符編碼弄清晰了,所以寫一篇文章來紀念一下,也爲大家提供一點自己的心得。<?xml:namespace prefix = o />

衆所周知,JAVA爲了國際通用,用的是UNICODE來保存裏面的字符。而UNICODE只是一個種字符集,字符的存儲和表示要用到一定的字符編碼格式,而與UNICODE對應的字符編碼格式就是我們常看到的UTF-8,UTF-16等等,而UTF-8是最常用的,所以人們常常把它和UNICODE等同起來(我以前就是這樣的),這在某些情況下是沒有錯的,但這樣的理解在JAVA裏就會產生一些混淆。我們用下面的程序來演示一下。

定義一個字符串

     String name = "堂";

這個字符串就一個字符,把它取出來

     char c_name = name.charAt(0);

JAVA裏的char型是十六位的(兩個字節),但是如果是用UTF-8的話可能會不只兩位(UTF-8是變長存儲的),那看來JAVA本身並不是用UTF-8來保存的,口說無憑,做個實驗吧。
    首先看看char裏保存的內容

int low = (c_name) & 0xff;//取c_name的低位

int high = (c_name >> 8) & 0xff;//取c_name的高位

System.out.println(Integer.toHexString(high) + " " + Integer.toHexString(low));

結果是58 02

只有兩個字節而已(16位),那麼真正的UTF-8編碼的內容是什麼呢,再看看吧。

爲了方便,我寫了一個輔助方法printbyte,作用是把一個byte數組的每個元素按照十六進制格式打印出來,同樣爲了方便,我把它作爲靜態方法。

     public static void printbyte(byte[] bt)

     {

         for (int i = 0; i < bt.length; i++)

         {

              int hex = (int)bt[i] & 0xff;

              System.out.print(Integer.toHexString(hex) + " ");

         }

         System.out.println("  length = "+bt.length);

}

     byte[] utf_8 = name.getBytes("utf-8");

printbyte(utf_8);

結果是e5 a0 82   length = 3

哇,三個字節!看來JAVA內部用的真不是UTF-8,那用的是什麼呢?UTF-16?看一下便知。

     byte[] utf_16 = name.getBytes("utf-16");

     printbyte(utf_16);

結果是fe ff 58 02   length = 4靠,四個字節了。咦?後面的低16位不正是和開始c_name的十六進制表示一樣的嗎?看來JAVA真正的內部字符編碼和UTF-16有或多或少的聯繫。JAVA內部究竟是用的什麼字符編碼呢?這個問題我也找了很久,後來在THINK IN JAVA 3rd的12章裏看到一個例子出現了UTF-16BE,難道是它?

     byte[] utf_16be = name.getBytes("utf-16be");

     printbyte(utf_16be);

結果出來了:58 02   length = 2

哈哈,I got it!不多不少兩個字節,內容也一樣。果然是它。同時我在裏面也看到,UNICODE的編碼還有一個LE,這裏的BE,LE我想應該是bigendian和littleendian吧。

    好了,JAVA裏字符的編碼總算搞清楚了,這是本人的第一篇原創文章,可能很膚淺。如果有什麼不對的地方請大家慷慨指教!謝謝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章