posts - 262,  comments - 221,  trackbacks - 0

Unicode中文“艺”字: 827A

二进制的“艺”字编码:1000 0010 0111 1010

UTF-8的中文编码规则: 1110xxxx 10xxxxxx 10xxxxxx

UTF-8的“艺”字编码: 1110【1000】 10【0010】【01】 10【11】【1010】

UTF-8的转码过程解析: 8对应的1000被填入第一字节剩余的4位。2对应的0010被填入第2字节剩余的前4位。7对应的0111被拆开,前2位01被填入第2字节的后两位,后2位1被填入第3字节的前2位。A对应的1010被填入第3字节的后4位。

UTF-8的最终编码结果:11101000---对应E8;10001001---对应89;10111010---对应BA。所以最终的UTF-8编码就是%E8%89%BA

Unicode到UTF-8的转换:Unicode的16进制编码<-->对应的2进制编码<-->UTF-8规范的2进制编码<-->UTF-8规范的16进制编码

也就是说假如在Java的底层JVM,由于采用的是Unicode编码字符集,对“艺”字的编码是827A。那么在网络传输的过程中,我们当然不能直接传输827A这个字符过去代表艺”这个汉字,而必须要转换成0,1这样的字节流,才能在网络中传输。

所以说UTF-8是一种为了方便网路传输,节省传输数量,而对Unicode的字符集的字符编号进行转换,从定长的2个字节(16进制)转换成1~3个的变长字节(2进制)表示的转换格式。

由于Unicode采用的是2个字节的编码方式,而UTF-8转换后可能是1~3个字节,所以同一个汉字,在Unicode中的编码和经UTF-8转换后的编码值肯定是不同的。就好像艺字的Unicode编码是827A,经转换后的3个字节是E889BA。

所以说对于英文字符来说,采用UTF-8对Unicode编码转换后节省了一倍的传输成本(由定长的2个字节变长1个字节),但对于原本双字节的东亚字符来说,反而增加了成本,是原来的1.5倍。

小结:

①ASCII、GB2312、GBK、GB18030、Big5、Unicode都是字符集的名称。它们定义了采用1~2个字节的编码规范,为每个字符赋予了一个独一无二的编号。这个编号就是我们所说的“字符编码”。

②Unicode字符集定义的字符编码并不适合直接通过网络传输表达,因为它们必须转换成像0101这样的二进制字节流传输。所以就出现了不同的转换规范实现方式:UTF-8,TF-16等。这些不同的转换规范转换后的编码值和Unicode是不同的。

对于UTF-8来说,它采用变长字节表示所有Unicode字符,对于英文来说和ASCII兼容,对于东亚字符来说,是原来传输成本的1.5倍。所以采用UTF-8编码转换方式虽然有利于统一,但增加了中文等双字节字符的传输成本。

UTF-8采用首字节的高位"1"的个数表示字符的编码长度。例如在Unicode的编码规范中:汉字的表示区间为U-00000800至U-0000FFFF对应的UTF-8的转换规则为:1110xxxx 10xxxxxx 10xxxxxx 首字节3个1代表这个字符的编码长度为3个字节。如果是2个1则表示2个字节

③在底层的平台中如JVM,采用的是Unicode字符集,当要把这些字符通过网络传输时,可以选择通过UTF-8或其他(例如GB2312)编码转换方式对要传输的字符编码进行转换。如果目的端也是采用Unicode字符集,那么UTF-8转换后的编码可以被正常识别并解码成最终对应的Unicode字符集编号。如果是非Unicode字符集平台则可能出现乱码(UTF-8中汉字的3个连续字节被解析成GB2312的2个连续字节,出现丢失)。所以推荐在传输的两端采用Unicode字符集编码,在传输方式上采用UTF-8转换方式。

javac命令是以系统默认编码读入源文件,然后按Unicode进行编码的。(备注:每个文件都有自己的编码,javac命令按照默认的文件编码读入,但是在将.java文件转换成.class的过程中,javac会将所有的字符转化成unicode的格式保存。)

在运行时JVM也是采用unicode编码的,并且默认输入和输出使用的都是操作系统的默认编码。也就是说在new String(bytes[,encode])中,系统认为输入的bytes是编码为encode的字节流(如果不指定encode,那么就是默认使用系统的编码方式),换句话说,如果按encode来翻译bytes才能得到正确的原始字符,这个字符最后要在java中保存,它还是要从这个encode转换成Unicode的。

也就是说,假如我们需要从磁盘文件、数据库记录、网络传输一些字符,保存到Java的变量中,要经历由bytes-->encode字符-->Unicode字符的转换(例如new String(bytes, encode));而要把Java变量保存到文件、数据库或者通过网络传输,系统要做一个Unicode字符-->encode字符-->bytes的转换(例如String.getBytes([encode]))



-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要尽力打好一手烂牌。
posted on 2010-02-16 23:23 Paul Lin 阅读(3665) 评论(3)  编辑  收藏 所属分类: J2SE


FeedBack:
# re: 【Java基础专题】编码与乱码(01)---编码基础
2012-12-12 16:16 | 砂银
非常有用,谢谢  回复  更多评论
  
# re: 【Java基础专题】编码与乱码(01)---编码基础[未登录]
2014-04-22 11:08 | 小龙
谢谢,帮了我大忙!  回复  更多评论
  
# re: 【Java基础专题】编码与乱码(01)---编码基础[未登录]
2016-04-04 14:16 |
666666666666666666666这几天正在做个类似工程编码出现错误  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
 
<2010年2月>
31123456
78910111213
14151617181920
21222324252627
28123456
78910111213

常用链接

留言簿(21)

随笔分类

随笔档案

BlogJava热点博客

好友博客

搜索

  •  

最新评论

阅读排行榜

评论排行榜