關於一個字符佔多少個字節的問題

首先解釋爲什麼說char佔兩個字節
Java code
?
1
2
3
4
5
6
public static void main(String[] args) {
    System.out.printf("The max value of type char is %d.%n"
            (int)Character.MAX_VALUE);
    System.out.printf("The min value of type char is %d.%n"
            (int)Character.MIN_VALUE);
}

運行上面的程序,輸出
The max value of type char is 65535.
The min value of type char is 0.
說明char的範圍從0到65535,那麼正好是兩個字節所能表示的範圍(65535十六進制就是0xFFFF,一個字節能表示0~0xFF,兩個字節能表示0~0xFFFF),所以說一個char佔兩個字節。

那麼char的值到底是什麼呢?比如當我這樣寫char c = '放';
Java code
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws Exception {
    char c = '放';
    System.out.printf("The value of char %c is %d.%n", c, (int)c);
     
    String str = String.valueOf(c);
    byte[] bys = str.getBytes("Unicode");
    for (int i = 0; i < bys.length; i++) {
        System.out.printf("%X ", bys[i]);
    }
    System.out.println();
     
    int unicode = (bys[2] & 0xFF) << 8 | (bys[3 0xFF]);
    System.out.printf("The unicode value of %c is %d.%n", c, unicode);
}

運行輸出:
The value of char 放 is 25918.
FE FF 65 3E 
The unicode value of 放 is 25918.
首先你看到,這個char的值是25918,那他是什麼呢?先不管它,接着我把這個char放在一個String裏,並進行Unicode編碼,得到四個字節FE FF 65 3E,前面兩個實際上與內容無關,是BOM,即字節序標識,FE FF表示是Big Endian,也就是高位在前,低位在後,所以按照這個規則,講653E轉換爲10進制int,發現最後輸出25918,也就是這個字符的Unicode值是25918,所以你現在知道一個char到底存儲的是什麼了吧。

至於GBK,UTF-8,UTF-16的關係,我先拋開GBK,因爲它有點特殊。
首先你要知道UTF-8和UTF-16還有UTF-32是爲了方便傳輸和存儲的而產生的對Unicode字符的編碼方式。
先說UTF-8,隨着全球化Unicode流行起來,不管你做什麼,支持Unicode都將是潮流,就算你可能永遠也用不到,但這對西方國家就不太好,因爲以前ASCII字符集,一個字符只需要一個字節,而現在用Unicode一個英文字母也需要兩個字節,如果需要傳輸和存儲,那會浪費一半的空間或流量,所以就想出了一種變長編碼方式,那就是UTF-8,它對ASCII字符集內的字符,只用一個字節編碼,而其他字符按照一定規則進行兩、三、四字節編碼,具體規則是:
Unicode編碼(十六進制)    UTF-8 字節流(二進制)
000000 - 00007F                0xxxxxxx
000080 - 0007FF                110xxxxx 10xxxxxx
000800 - 00FFFF               1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF               11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

但這樣做一些東方國家不幹了,因爲他們的字符基本都是在000800 - 00FFFF這個區間,用UTF-8反倒要多用一個字節,總共需要三個字節才能表示,而且用UTF-8處理他們的字符,不能直接轉換,需要做一些運算,以‘放’爲例,它的Unicode碼是25918,二進制表示是0110010100111110,如果要轉成UTF-8,首先取高四位0110,和1110拼接,組成11100110,然後中間六位010100,與10拼接構成10010100,最後低六位111110,與10拼接構成10111110,所以三個字節是11100110 10010100 10111110,也就是十六進制的E6  94 BE,也就是你上面寫的-26 -108 -66。可以看到這個運算量雖然不大,基本是位操作,但如果你每個字符都要這麼操作實在是有損效率,綜合這幾點考慮,於是又弄了一個UTF-16,不嚴謹地來說它等價於Unicode原生編碼,它統一採用雙字節表示一個字符(其實有四字節區域,但現在一般沒有用到),而由於它用多字節表示,和Unicode一樣需要字節序標識,你上面代碼裏發現它得到-2, -1, 101, 62,轉爲十六進制就是FE FF 65 3E,和我第二個實例程序中相同,說明UTF-16的碼值(如表示‘放’的65 3E)和Unicode原生編碼是相同的。

UTF-32的誕生其實也不奇怪,因爲UTF-16還是一個變長編碼方式,一個字符可能由兩個或四個字節表示,有些有強迫症的人總覺得不好,所以爲了他們就有了UTF-32,它統一使用四字節表示一個字符,因爲用得不多所以不詳細說了。

最後說說GBK是個什麼東西。GBK是國標擴(展)的拼音首字母,是我國在1995年制定的專門針對漢語和一些少數名族語言的編碼方式,和Unicode之間沒有一一對應的關係,也就是說Unicode中有的字符GBK不一定有,GBK有的字符Unicode也不一定有,而且GBK和Unicode中共有字符,他們的編碼值沒有一種簡單的對應關係,也就是無法通過簡單計算得到,只能通過查錶轉換。爲什麼會有GBK這種奇葩呢?其實是當時Unicode還沒制定好,更沒在全球範圍內推廣,而中國人要用電腦總不可能永遠用英語吧?所以我國就自行制定了一個國標,當時是GB2312,(其實臺灣地區針對繁體還有一個Big5,但這裏就不詳述了),GB2312後來增加了很多字符,包括很多少數名族的語言,成爲了一個新的編碼標準,那就是GBK。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章