Java中的UTF-8、UTF-16編碼字符所佔字節數

前言:上一篇文章寫了關於Unicode,以及utf-8、utf-16相關知識。所以本篇博文來驗證在java環境下,字符在不同編碼下所佔的字計數。

測試代碼如下:

package string;

public class CharByteTest {

    public static void main(String[] args) throws Exception {
        // 第二個字符爲BMP之外的字符,csdn編輯器無法顯示該字符,可以在運行結果截圖中看到
        String[] strArr = {"中", "��", "a", "aa"};
        String[] charsetArr = {"gbk", "utf-8", "utf-16", "gb2312"};
        for(String str : strArr) {
            System.out.println(str);
            for(String charset : charsetArr) {
                byteTest(str, charset);
            }
            System.out.println("============================");
        }
    }

    public static void byteTest(String str, String charset) throws Exception {
        System.out.println("編碼:" + charset 
                + "\t所佔字節數:" + str.getBytes(charset).length);
    }

}

運行結果如下:

這裏寫圖片描述

在前一篇文章的基礎上,我們來分析一下運行結果。

  1. “中”字的unicode碼值爲4E2D,使用UTF-8編碼佔3個字節。由於該字符位於BMP內,所以使用UTF-16編碼應該佔2個字節,但是運行結果爲4個字節。
  2. 第二個字符(csdn編輯器不支持該字符的顯示),該字符使用UTF-8應該佔4個字節,運行結果正確。由於該字符位於BMP外,所以使用UTF-16編碼應該佔4個自己,但是運行結果顯示佔用了6個字節。
  3. 英文字母a,UTF-8編碼應該和ASCII編碼相同佔用一個字節,運行結果顯示佔用一個字節。a在Unicode中位於BMP內,所以UTF-16編碼應該佔用4個字節,但是運行結果缺顯示4個字節。
  4. 按照上面的運行結果,a在UTF-8編碼下佔用1個字節,在UTF-16編碼下佔用4個字節。那麼猜測兩個英文字母a,即”aa“在UTF-8和UTF-16編碼下應該分別佔2個和8個字節,但是運行結果卻和想象中的不一樣,aa在UTF-16編碼下工佔6個字節。

運行結果好像和上一篇中講到的有點不相符啊!爲什麼會出現這樣的結果的?

通過搜索相關文章,瞭解到java的字節碼文件(.class)文件採用的是UTF-8編碼,但是在java 運行時會使用UTF-16編碼。在轉碼的時候會在前面加上表示字節順序的字符,這個字符稱爲”零寬度非換行空格”(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。FEFF佔用兩個字節,所以就解釋了爲什麼java環境下英文字母a在UTF-16編碼佔3個字節。

我們不妨將這些字符的在不同編碼下的二進制轉換爲16進制並打印出來。
將代碼修改如下:

package string;

public class CharByteTest {

    private static char[] HEX_CHAR = {'0', '1', '2', '3', '4',
            '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static void main(String[] args) throws Exception {

        String[] strArr = {"中", "��", "a", "aa"};
        //String[] charsetArr = {"gbk", "utf-8", "utf-16", "gb2312"};
        String[] charsetArr = {"unicode", "utf-8", "utf-16", "utf-16BE", "utf-16LE"};
        for(String str : strArr) {
            System.out.println(str);
            for(String charset : charsetArr) {
                byteTest(str, charset);
            }
            System.out.println("============================");
        }
    }

    public static void byteTest(String str, String charset) throws Exception {
        byte[] strByte = str.getBytes(charset);
        System.out.println("編碼:" + charset 
                + "\t所佔字節數:" + strByte.length
                + "\t16進制:" + bytesToHexStr(strByte));
    }

    // 將byte[]用十六進制字符串
    public static String bytesToHexStr(byte[] bytes) {
        int index = 0;
        char[] hexChar = new char[bytes.length * 2];
        for(int i = 0; i < bytes.length; i++) {
            hexChar[index++] = HEX_CHAR[bytes[i] >> 4 & 0xF];
            hexChar[index++] = HEX_CHAR[bytes[i] & 0xF];
        }
        return new String(hexChar);
    }

}

運行結果:
這裏寫圖片描述

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