char如何存UTF-8字符?
UTF-8的由来
我们知道char是占两个字节的这个大家都知道,那UTF-8是什么呢?我们见得比较多,真正能说清楚的也不见得都能做到,在谈到UTF-8
,我们不得不谈下Unicode
,对于有些人来说Unicode可能稍微陌生点,但是说到ASCII
码估计大家都知道。
简单说明下,我们知道计算机只能识别0和1,那么如何将我们这个世界中如此众多的文字呈现或者传播呢?美国人搞了个ASCII码就是一个将英文中的字母和一些特殊符号一共128种,使用7位二进制数字一一对应起来(说白了就是符号和7位二进制数的映射表)。
计算机中每八位二进制组成一个字节,它是计算机存储的最小单位。那么我们就可以用一个字节,最高为用0占位就完全足够标识英文中的任何字母了,这样就可以将英文在计算机中进行无压力的传播啦。(举个例子:字母“A”对应的二进制数为“01000001”即十进制的41)不错!这确实解决了美国的问题,可是世界上那么多国家的不同文字字符,不全是英文字母啊,这怎么行呢?
于是Unicode
诞生了,他将编号范围扩大为0x000000~0x10FFFF
来将世界上绝大多数的字符一一映射起来了。(Unicode可以说是对ASCII的补充,它也是一个字符集)比如中文“马”字,对应的唯一的Unicode编号为U+9A6C(16进制的表示方式)。
注意Unicode只是规定了字符的编号,并没有说明以什么样的形式存储,你可以说直接将编号转换成二进制进行存储不就可以了吗?不错,这么做确实可以,但是会带来几个问题?
如何和ASCII码区分开来,计算机无法知道三个字节表示一个字符还是三个不同的字符?
英文字符只需要一个字节就能表示完,如果Unicode统一说使用三个或者四个字节表示一个字符,那么对于英文字符存储空间造成很大的浪费
所以,出现了很多中来实现Unicode编码方式,UTF-8就是其中一种,他是一种变长的编码方式,比如英文字符他只使用一个字节存储,按照不同的Unicode编号,将他们划成四个范围,分别对应使用一个、两个、三个、四个字节。
而且编码规则简单,便于计算机判断当前多少个字节表示一个字符。比如检测到当前字节以0开头,那么当前字节就对应一个字符,如果开头是“1”,那么开头有多少个连续的“1”就表示当前这个字符占用多少个字节来存储。
以上,让我们知道了UTF-8其实就是Unicode字符集的一种编码方式,它可能会占用1~4个字节。
回归问题
那么,回到最初的问题,char是两个字节的,那么怎么使用char类型存UTF-8编码的字符呢(可能会是3或者4个字节)?
其实,我们可以定义一个char类型的数据赋值为'庆','庆'使用utf-8编码后为:e5ba86,不错是三个字节,三个字节怎么赋值给只占两个字节的char类型变量呢?可是事实是确实可以赋值的:
char test = '庆';
确实编译器没有报错,咋回事呢?这里就是大家的误区了。其实'庆'使用utf-16
进行编码无论是大尾序utf-16BE(5E86)
还是使用小尾序utf-16LE(865E)
进行编码都是占用两个字节也就是一个字符的。
所以,我们要了解一个事实就是JVM中对char是使用UTF-16编码的。使用UTF-16的好处是大部分字符都能以固定两个字节存储,但是这样的坏处就是对于英文字符存储就造成浪费。
为了解决这个问题,Java9以后对字符串做了优化,对于字符串里面都是拉丁字母或者ASCII码中的字符,不使用UTF-16编码存储,而是使用byte存储,这样可以省一部分空间。
未经允许请勿转载:程序喵 » char 类型如何存储一个汉字的?