java 中文字符串,utf-8编码为byte数组的计算过程
背景:
对于编码解码的计算过程一直没有去研究过。以前也看了大神写的编码解码的文章,当时看了似懂非懂,没有仔细去品味,没去实践。正应了那句老话:纸上得来终觉浅,绝知此事要躬行。
为什么有编码和解码?二什么时候会出现编码和解码?编码解码的算法是怎样的?
推荐两篇文章
http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
http://blog.csdn.net/baixiaoshi/article/details/40786503
已经回答的很好了,^^偷懒不写了。
基础知识:
unicode转换为utf-8编码的规则
Unicode UTF-8
0000-007F 0xxxxxxx
0080-07FF 110xxxxx 10xxxxxx
0800-FFFF 1110xxxx 10xxxxxx 10xxxxxx
如果字符对应编码值小于0x7F,则转换该为1个byte,最高位为0(0x7F转换为二进制为111111,7个1。不会出现最高位为1,最高位为1肯定大于7F。),该字符对应的二进制替换X,不足7位前面高位加0
编码值在0080到07FF字符,会转换为2个字节,并且第一个字节以110开头,第二个字节以10开头,字符对应的编码值转换为2进制后的数据,填充X。不足位数的高位加0
编码值在0800到FFFF字符,会转换为3个字节,并且第一个字节以1110开头,后面字节以10开头,字符对应的编码值转换为2进制后的数据,填充X。不足位数的高位加0
也就是说大于07XX编码值的字符,转换为字节时,第一个字节中连续1的个数表示该字符对应字节的长度
计算过程
String name = "中";
char[] chars = name.toCharArray();
//使用utf-8编码字符集
Charset charset = Charset.forName("utf-8");
CharBuffer charBuffer = CharBuffer.allocate(chars.length);
charBuffer.put(chars);
charBuffer.flip();
//字符编码为字节数组
ByteBuffer byteBuffer = charset.encode(charBuffer);
byte[] charToBytes = byteBuffer.array();
System.out.println("chars.length:" + chars.length+";bytes.length:" + charToBytes.length);
byte[] bytes = name.getBytes("utf-8");
运行后byte数组值,可通过debug查看
转换过程
“中”的unicode通过查unicode编码表可知为:4E2D(十六进制的数,附件是网上找的一个编码表),通过转换为二进制:100111000101101。4E2D落在了0800~ FFFF区间内,再依据前面转换规则填充x。
填充过程:
最后获得 11100100 10111000 10101101。
二进制到byte的换算过程
根据1个字节占8位,换算为字节数组[224,184,173],这和程序运行结果[-28,-72,-83],对不上,脑袋当时就卡了。然后一想不对呀,java中byte的范围是-128到127,手工算出来的是224,184,173这明显超出了byte数值的范围。又一想这都是按无符号数进行二进制转换为byte。查了下无符号数转换为有符号数的规则(也有说这是补码):最高位用来表示符号,其余按位取反再加1。
按位取反 加1
11100100--------------->10011011-------------> 10011100
最高位为符号位不参与计算,剩下的二进制0011100转换为十进制为 28,加上符号为-28
同理
10111000转换后的十进制为 :-72
10101101转换后的十进制为:-83
最终和程序运行结果一样。