Java中一個字符用unicode編碼為什么不是兩字節


按照之前對Unicode及utf-8的描述,一個字符以Unicode編碼應該是2個字節,英文字符用utf-8占一個字節,中文可能是3-4個字節。那么我們來看看這段代碼的運行結果。

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
/**
 * @author qiang.xie
 * @date 2017/9/7
 */

public class Test {
    public static void main(String[] arg) throws Exception{
        String s1="a好";
        printBytesLen(s1,"gbk");
        printBytesLen(s1,"utf-8");
        printBytesLen(s1,"utf-16");
        printBytesLen(s1,"unicode");
        printBytesLen("h","utf-8");
        printBytesLen("h","unicode");
        printBytesLen("h","utf-16");
    }
        
    public static void printBytesLen(String string, String charset)
     throws UnsupportedEncodingException {
           byte[] bytes=string.getBytes(charset);
           System.out.println("["+string+"]使用["+charset+"]占用的字節長度:"+bytes.length+";十六進制:"+bytesToHex(bytes));
    }  
             
    //轉16進制
    public static String bytesToHex(byte[] bytes){
         return new BigInteger(1,bytes).toString(16);
    }
}

運行結果:

[a好]使用[utf-8]占用的字節長度:4;十六進制:61e5a5bd
[a好]使用[utf-16]占用的字節長度:6;十六進制:feff0061597d
[a好]使用[unicode]占用的字節長度:6;十六進制:feff0061597d
[h]使用[utf-8]占用的字節長度:1;十六進制:68
[h]使用[unicode]占用的字節長度:4;十六進制:feff0068
[h]使用[utf-16]占用的字節長度:4;十六進制:feff0068

我猜你們又要凌亂了。

為什么用unicode或utf-16總數要多出兩個字節?且聽我一一道來。

二進制的高低位

一個16位的二級制數符占兩個字節的存儲空間,即高位字節和低位字節。如果你是在紙上書寫一個16位的數,你總是會把高位字節寫在前面,而把低位字節寫在后面。然而,當這個數被存儲到計算機中時,並沒有固定的存儲順序。

如果我們用M和L分別表示高位字節和低位字節,那么可以有兩種方式把這兩個字節存儲到計算機存中,即M在前L在后或者L在前M在后。

把M存儲在前的順序被稱為“正向(forward)”或“高位優先(big—endian)”順序;把L存儲在前的順序被稱為“逆向(reverse)”或“低位優先(little—endian)”順序。

big—endian這個術語的含義是數的“高位(big end)”存儲在前。

大多數計算機按正向順序存儲一個數,Intel CPU按逆向順序存儲一個數,因此,如果試圖將基於Intel CPU的計算機連到其它類型的計算機上,就可能會引起混亂。另外,當字節流在網絡上傳輸時,如果你從高位到低位的順序發送,接受者卻以低位到高位的順序結束,也會發生混亂。

那么,怎樣明確的通過一些方式來表明字節的高低位順序呢?

BOM

BOM(Byte Order Mark),字節順序標記。

unicode編碼規范中編碼中有一個叫做 "Zero Width No-Break Space" ,中文譯名作“零寬無間斷間隔”的字符,它的編碼用十六進制表示是FEFF。而 FEFF 在 unicode 中是不存在的字符,所以不應該出現在實際內容中。unicode 規范建議我們在傳輸字節流前,先傳輸這個FEFF。這樣如果接收者收到 FEFF,就表明這個字節流是Big-Endian(高位在前) 的;如果收到FFFE,就表明這個字節流是 Little- Endian(低位在前)的。因此字符 "Zero Width No-Break Space" (“零寬無間斷間隔”)又被稱作 BOM。

說白了就是用一個專門的unicode字符來加在實際內容的前面,來告訴使用者我這個內容里的字節順序是高位在前還是低位在前的。

如此一來,上面程序的結果也就能解釋的通了。

基於unicode(utf-16)的編碼總會比實際內容多出兩個字節,就是那個BOM,它也是一個unicode字符,所有也需兩字節。

而utf-8編碼有自己特殊的特征,它完全可以根據自己的編碼方式避免這個高低位順序的問題,所以不需要BOM。

 

轉載:https://mp.weixin.qq.com/s?timestamp=1510898006&src=3&ver=1&signature=SZlSxEWJYVinrj2MnVMDESmG2QNKElpjfJi0dW2v7FNUTVW8fikv2qxfIN8w10WiffqgevZnxVfxNpKgrni5jG5Hk28KXKjI--7lQHE*ac6EpWFtGJkYjzfxScB3F6yyrPilkbvCUJ4KruGSbajdwkMbhTE3BY1Q9yFcbhpahr0=

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM