分享

Java中一个字符到底多少个字节

 gaoshenmu 2016-09-22
前言:
如果你一看这个标题的第一反应是“java使用unicode编码,地球人都知道是2个字节呀”,如果你的认识也是这样的,看完本文一定会有所收获,如果你的回答是在内存中有些字符使用2个字节表示,有些使用4个字节表示,那么你的认识完全碾压本博文的内容,可以笑笑的离去。
注:由于我当前的wordpress使用的mysql 不支持unicode扩展字符集,所以只能用0×20001 来代替具体的字符。大家在运行代码的时候content:|0×20001| 输出的是具体的字符。
java.lang.Character类的javadoc中,对这个问题有完美答案,大致为:
一个字符的Unicode编码的专业术语叫code point, 如果一个字符的编码属于U+0000 到 U+FFFF范围,那么可以使用2个字节表示,这个范围不能表示全天下所有的字符,比如“0×20001”。unicode在这个的基础上制定了一个扩展集,对于的范围为U+10000到U+10FFFF,这个范围的字符有个名字叫做“supplementary characters”,它们将占用四个字节。所以在java中并不是一个char 对应一个字符,对于扩展集中的字符,而是一个对应两个字符。不信?请看下面的示例:
1
2
3
4
5
6
public static void main(String[] args) throws Exception {
char[] arr = Character.toChars(0x20001);
System.out.println('char array length:' + arr.length);
System.out.println('content:|' + new String(arr) + '|');
System.out.println('String length:' + new String(arr).length());
}
输出为:
char array length:2
content:|0×20001|
String length:2
看到了吧,确实如此,这也解释了为什么Character类的很多函数都有参数为int的版本,因为有些字符是不能用一个char表示的。
下面我们再看看String.getBytes()方法
因为很多童鞋都认为String.getBytes().length返回的值是该字符在内存中对应的字节数的证据,其实不然。String.getBytes()是使用系统默认字符集处理后的结果,这个可以查看相应源码确认。在启动程序时我们可以通过更改file.encoding属性(“java -Dfile.encoding=utf-8 待执行的类”), 在Eclipse中可以通过Run configurations->Common->Encoding来更改
,如图:
捕获 - 副本
注(encoding的Other 选项是支持输入的,当没有“GBK”选项时可以手动输入这个值然后单击确定。还有“0×20001”没有收录在GBK当中,范围比它还大的GB18030才含义该字符。)。
修改我们的示例代码为:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) throws Exception {
//char[] arr = Character.toChars(0x20001);
Strings = new String('知');
//System.out.println('char array length:' + arr.length);
System.out.println(s);
System.out.println('String length:' + s.length());
System.out.println('default charset:' + Charset.defaultCharset());
System.out.println(s.getBytes().length);
for(byte b : s.getBytes()) {
System.out.print(toHex(b));
}
}
public static String toHex(byte b) {
char[] hexs = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F' };
String s = '';
s += hexs[(b >> 4)
s += hexs[b
return s;
}
由于“0×20001”太特别了,基本每种编码都对其进行了特殊的处理,GB18030,utf-8, utf-16BE对对其使用了四个自己存放,在上面的例子中我们使用了一个普通的“知”作为示例,我们发现当编码为gbk18030时输出的长度为2,当编码为utf-8时长度为3。
结束语:
语言编码从ANSI的各自为营到unicode一统江湖,这是一个历史的演变。有时它给我们的工作带来了小小的麻烦,但是当我们熟悉它,就可以从容面对。
参考文档:
1.java.lang.Character javadoc
2.rfc2781.txt (utf-16的规范,百度一下就能找到)
3.http://blog./unicode-intro/#content_2_6 ( 一个高手在n年前对各自编码的总结)

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多