按照之前对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=