Java使用UTF-16而不是更节省内存的UTF-8是因为UTF-16可以做到大部分常见的文字按2个字节存储,少量不常见的字符按4个字节存储,统计和定位字符的效率比UTF-8高。而UTF-8划分的变长空间多,这方面是个不能忽视的短板。
所谓UTF-8更节省内存的说法,对广大东亚文字来说根本就是伪命题。UTF-8更省内存只有在文本内绝大部分是ASCII的字符下才成立,也就是只需要一个字节即可表示一个字符,比如英文字母、数字、半角标点符号等。而东亚文字,比如常见的汉字,用UTF-8传输和存储则需要3个字节。相比之下,UTF-16对大部分常见文字只需要2个字节,不常见的文字才需要4个字节。谁更节省内存取决于内容,而不是编码本身。
Java 当时选择了 UCS-2 与 Windows 一致,而 UCS-2 是定长编码。后来,BMP 已经不够表示 Unicode 了,UCS-2 无法表示,于是就有了 UCS-4,虽然 UCS-4 暂时可以保证定长,但 UCS-4 会显得过于浪费内存。于是,就回到了变长编码。
变长编码是用 UTF-8 还是 UTF-16?显然 UTF-8 有很多优势,因为 UTF-8 在7bit区域跟 ASCII 兼容,而 UTF-16 仅仅只在 BMP 区域与 UCS-2 兼容。
当初用 UCS-2 是因为它定长,而随着 Unicode 字符数量的暴增,UCS-2 无法定长,就变成了一个相对鸡肋的编码,为了保持兼容性只能继续存在。
UTF-16除了兼容UCS-2以外并无明显优势,毕竟UTF-16是变长编码。
来源:https://www.zhihu.com/question/308677093/answer/2748610506
https://www.zhihu.com/question/308677093/answer/2745757552
延伸阅读
UTF-8和UTF-16的区别
1、主要的UTF-8优点:
- 基本的ASCII字符如数字,没有重音的拉丁字符等占用一个与US-ASCII表示相同的字节。 通过这种方式,所有US-ASCIIstring都变成了有效的UTF-8,在很多情况下它提供了不错的向后兼容性。
- 没有空字节,它允许使用以空字符结尾的string,这也引入了大量的向后兼容性。
- UTF-8与字节顺序无关,因此您不必担心Big Endian / Little Endian问题。
2、主要的UTF-8缺点:
- 许多常见的字符长度不同,这会减慢编码点的索引,并可能会严重计算编码点数。
- 即使字节顺序并不重要,但有时UTF-8仍然具有BOM(字节顺序标记),用于通知文本以UTF-8编码,并且即使文本只包含ASCII字符也不兼容ASCII软件。 微软软件(如记事本)特别喜欢把BOM添加到UTF-8。
3、主要的UTF-16优点:
- BMP(基础多语言平面)字符,包括拉丁文,西里尔文,大多数中文(中华人民共和国支持强制性BMP以外的一些代码点),大多数日文可以用2个字节表示。 如果文本不包含补充字符,这将加快索引和计算代码点数。
- 即使文本具有补充字符,它们仍由16位值对表示,这意味着总长度仍可被2整除,并允许使用16位
char
作为string的基本组成部分。
4、主UTF-16缺点:
- 在US-ASCIIstring中有很多空字节,这意味着没有以空字符结尾的string和大量浪费的内存。
- 在许多常见情况下(特别是在美国/欧盟/西里尔字母/以色列/阿拉伯国家/伊朗等国家),使用它作为固定长度编码“通常会起作用”,如果不这样做,通常会导致断开的支持。 这意味着程序员必须注意代理对,并在重要的情况下正确处理它们!
- 它的长度是可变的,所以对码点进行计数或索引是很昂贵的,尽pipe比UTF-8less。
一般来说,UTF-16通常比内存表示更好,因为BE / LE在那里是不相关的(只是使用本地顺序),索引更快(只是不要忘记正确处理代理对)。 另一方面,UTF-8对于文本文件和networking协议是非常好的,因为不存在BE / LE问题,空终止常常派上用场,而且兼容ASCII。
文章标题:Java为什么使用UTF-16而不是更节省内存的UTF-8,发布者:小编,转载请注明出处:https://worktile.com/kb/p/37293