为什么UTF-8中3字节特殊字符仅让字符串总长度增加1?
问题根因分析
- 你混淆了两个完全独立的概念:编码后字节数组的长度和
Java String.length()的返回值
你计算的15+3=18是「字符串用UTF-8编码后的总字节数」,这个计算本身是对的:15个ASCII字符每个在UTF-8下占1字节,特殊字符ࢤ(Unicode码点U+08A4,属于阿拉伯语补充区块)是BMP平面字符,UTF-8编码占3字节,总字节数确实是18字节。 - Java的
String.length()返回的从来不是字节数,而是字符串包含的UTF-16代码单元数量。所有码点在U+0000~U+FFFF(即BMP基本多文种平面)内的字符,每个都只占用1个UTF-16代码单元,因此length()返回值等于字符串的字符总数。你测试的原字符串一共是15个普通ASCII字符加1个ࢤ,总共16个字符,只要字符串内容没有损坏,length()必然返回16。 - 你写的测试代码本身存在逻辑错误:
new String("xxx".getBytes(指定编码))这种写法会产生乱码。你用指定编码把字符串转为字节数组后,调用new String(byte[])时会用JVM的默认编码去解码字节数组,如果默认编码和你转字节用的编码不一致,就会直接生成乱码字符串。你打印出来的16、32、64其实是乱码后的字符串的长度,完全不是你预想的对应编码的字节长度。
正确的测试写法
如果你要统计不同编码下的字节长度,应该直接统计getBytes()返回的字节数组的长度,不要转成String再统计:
public class TestEncoding { public static void main(String[] args) throws Exception { String str = "Hi how are you?ࢤ"; System.out.println("UTF-8 字节数:" + str.getBytes("UTF-8").length); System.out.println("UTF-16LE 字节数:" + str.getBytes("UTF-16LE").length); System.out.println("UTF-32 字节数:" + str.getBytes("UTF-32").length); } }
运行后输出结果就会符合你的预期:
UTF-8 字节数:18 UTF-16LE 字节数:32 UTF-32 字节数:64
内容的提问来源于stack exchange,提问作者Uncle Iroh
相关产品推荐
相关产品推荐

