- 字符集与字符编码、码点
- ASCII
- ISO-8859-1(Latin 1)
- GB2312、GBK、BIG5
- GB2312
- BIG5
- GBK
- 乱码
- Unicode字符集
- 代码单元
- UTF-32
- UTF-8
- UTF-16
- 高位代理项与低位代理项
- 自同步的字符编码
- Java String
- Java 8及以前
- Java 9及以后
- 字符集:存放了字符与数字的映射关系
- 码点(code point):不同的字符对应不同的数字,这个数字就是码点
- 字符编码:通过字符集可以知道一个字符对应的数字,所以计算机需要先通过一定的规则将这个二进制的bit数转为十进制整数,才能从对应的字符集中找到这个二进制bit数对应的具体字符。而这个规则就是字符编码,对于除了Unicode字符集以外的其它字符集都是简单的将二进制转为十进制数,所以对于这些字符集而言,字符集和字符编码并无什么不同
- 单字节的字符集,此时字符集就等同于字符编码,因为码点和二进制bit数之间只有简单的二进制转成十进制
- 总共占用7bit,对于计算机中包含8bit的一个字节的基本单位而言,最高位没有被用到,一般用来做奇偶校验位或直接补零
- 优点是简单,只包含可输出字符(如数字、大小写字母、英文符号等)和控制字符;没有特殊的字符编码规则,字符集等同于字符编码
- 缺点是表示的字符太少,对于非英文字符无法表示
- 对ASCII的改进,新增了其它可输出字符和控制字符,使得一个字节8bit能刚好被用完
- 优点是保留有ASCII原有有点的基础上一定程度上扩充了ASCII字符集的表示字符范围
- 缺点依然是表示的范围太小
- B2312主要针对简体中文,BIG5主要针对繁体中文
- GB2312兼容ASCII,因为GB2312不管是高位字节还是低位字节都大于128
- “訏功蓋”问题: BIG5字符集的低位字节与ASCII有冲突,虽然遇到问题的概率较低,但是还是会出现问题
- “”在很多编程语言中都是作为转义字符
- 当输入文本使用的字符集与读取文本使用的字符集不一致且两种字符集不兼容时就会导致乱码
- 是定长的字符编码,将每一个字符的码点固定的与一个四字节长度的二进制数相对应,所以UTF-32的代码单元(code unite)是4字节
- 优点是能够表示目前常用的所有字符,缺点是浪费空间,需要补充太多的0,导致固定长度的字节流能够表达的字符数字减少
- UTF-8是一种可变长度的字符编码,有特定的规则将二进制数转换为码点,针对不同范围的码点使用不同长度的二进制数表示,最低是1个字节,所以 UTF-8的代码单元是1字节
- UTF-8的优点是能够表达几乎所有常用的字符,且完美兼容ASCII字符集,变长的特性使得固定长度的字节流能够表达更多的字符
- UTF-16字符编码是可变长的字符编码,对于字符对应的码点和二进制数之间采用特定的规则进行相互对应,一般采用2个或4个字节的二进制数对应一个码点
- UTF-16缺点时对于单字节表示的字符会浪费一个字节的空间,全部补0
- 自同步是指,对于根据不同字符编码在二进制字节流中划分出来的代码单元,对于单独的每个代码单元在不追溯前面代码单元的情况下能识别出来其是否为某个字符的起始代码单元
- 对于Java 8及以前,String使用UTF-16作为字符编码,并使用char数组来存储数据
- char数组中的每一个char对应的不是字符而是UTF-16中的代码单元,根据代码单元编码完以后才是对应的字符,比如下图的表情字符其实对应两个char
- 在Java 8中计算字符长度,不应该使用String.length()而是应该使用String.codePointCount()
- 在Java 8中获取字符串中某个位置上的字符时,不应该使用String.charAt(),而是应该使用String.codePointAt()
- 由于UTF-16的缺点,Java 9以后对于String的字符编码使用了两种字符编码分别是Latin 1和 UTF-16,存储数据也从原来的char数组改为byte数组



