学习Java的时候,一开始书上就会说Java使用的UTF-16作为字符编码格式,因此相较于C语言,Java可以用中文等非拉丁字母作为变量名。
Unicode
unicode是计算机科学领域里的一项业界标准,包括字符集、编码方案等。计算机采用八比特一个字节,一个字节最大整数是255,还要表示中文一个字也是不够的,至少需要两个字节,为了统一所有的文字编码,unicode为每种语言中的每个字符设定了统一并且唯一的二进制编码,通常用两个字节表示一个字符(少则1个字节,多则3个字节),所以unicode每个平面可以组合出65535种不同的字符,一共17个平面。
字符集和字符编码不是一个概念,字符集定义了文字和二进制的对应关系,为字符分配了唯一的编号,而字符编码规定了如何将文字的编号存储到内存中。
例如:ASCII码中一个字符对应的是7位二进制数(字符集),计算机中一个字节是8位,我们用一个字节存储一个ASCII字符(一种编码方式)。当然,我们也可以用7个字节存8个字符,不过这样就不利于数据的读取与存储。所以不同的字符编码方式会使得字符在内存中的存储方式完全不同。
UTF 是 Unicode Transformation Format 的缩写,意思是“Unicode转换格式”,后面的数字表明至少使用多少个比特位(Bit)来存储字符。
Unicode 可以使用的编码有三种,分别是:
UFT-8:一种变长的编码方案,使用 1~4 个字节来存储;
UFT-32:一种固定长度的编码方案,不管字符编号大小,始终使用 4 个字节来存储;
UTF-16:介于 UTF-8 和 UTF-32 之间,使用 2 个或者 4 个字节来存储,长度既固定又可变。
UTF-8
Unicode和ASCII不同,他是变长的字符集,所以每个字符的长度不一定相同,所以编码方式也有多种,例如:广为人知的UTF-8。由于每个字符占用的字节数不同(1~3个字节),所以读取时就不能像ASCII码那样---一个字节对应一个字符,因为并不知道该字符占用了几个字节。因此,UTF-8编码会在第一个字节指明这个字符的长度(如果是单字节字符就不需要)。
UTF-8 的编码规则很简单:如果只有一个字节,那么最高的比特位为 0;如果有多个字节,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。
UTF-32
UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符。
UTF-16(Java中使用的字符串编码方式)
UFT-16使用 2 个或者 4 个字节来存储。
对于 Unicode 编号范围在 0 ~ FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。
对于 Unicode 编号范围在0x10000~10FFFF 之间的字符,UTF-16 使用四个字节存储,具体来说就是:将字符编号的所有比特位分成两部分,较高的一些比特位用一个值介于 D800~DBFF 之间的双字节存储,较低的一些比特位(剩下的比特位)用一个值介于 DC00~DFFF 之间的双字节存储。
编码范围10000 ~ 10FFFF中间存在0x100000=2^20个字符,这些字符的高10位用一个双字节存储,低10位也用一个双字节存储。既然是双字节,那么不可避免的会与0 ~ FFFF之间的字符冲突,所以这两个区间(D800 ~ DBFF,DC00 ~ DFFF)并没有定义字符。
Java中的字符(编号在内存中的存储)
谈到Java中的字符,其实也就是字符编号如何存储到内存(char[])中。
字符编号是一个32位int型。
当编号在0 ~ FFFF时,只需要一个双字节就可以存储了;当编号在10000 ~ 10FFFF时会被拆分为两部分放到两个双字节中。
Java中的String其实内部就是一个char[]
JDK源码
image1.pngimage2.png
image3.png
网友评论