乱码
我们来看一个这种错误转换后的乱码,还是用上节的例子,二进制是(16进制表示):C3 80 C3 8F C3 82 C3 AD,无论按哪种编码解析看上去都是乱码:
这几种格式之间可以借助Unicode编号进行编码转换。可以简化认为,每种编码都有一个映射表,存储其特有的字符编码和Unicode编号之间的对应关系,这个映射表是一个简化的说法,实际上可能是一个映射或转换方法。
编码转换的具体过程可以是,比如说,一个字符从A编码转到B编码,先找到字符的A编码格式,通过A的映射表找到其Unicode编号,然后通过Unicode编号再查B的映射表,找到字符的B编码格式。
举例来说,"马"从GB18030转到UTF-8,先查GB18030->Unicode编号表,得到其编号是9A 6C,然后查Uncode编号->UTF-8表,得到其UTF-8编码:E9 A9 AC。
与前文提到的切换查看编码方式正好相反,编码转换改变了数据的二进制格式,但并没有改变字符看上去的样子。
我们举个例子来说明:
两个字 "老马",本来的编码格式是GB18030,编码是(16进制): C0 CF C2 ED。
这个二进制形式被错误当成了Windows-1252编码, 解读成了字符 "ÀÏÂí"
随后这个字符进行了编码转换,转换成了UTF-8编码,形式还是"ÀÏÂí",但二进制变成了:C3 80 C3 8F C3 82 C3 AD,每个字符两个字节。
这个时候,再按照GB18030解析,字符就变成了乱码形式"脌脧脗铆", 而且这时无论怎么切换查看编码的方式,这个二进制看起来都是乱码。
这种情况是乱码产生的主要原因。
这种情况其实很常见,计算机程序为了便于统一处理,经常会将所有编码转换为一种方式,比如UTF-8, 在转换的时候,需要知道原来的编码是什么,但可能会搞错,而一旦搞错,并进行了转换,就会出现这种乱码。
char的本质
在Java内部进行字符处理时,采用的都是Unicode,具体编码格式是UTF-16BE。简单回顾一下,UTF-16使用两个或四个字节表示一个字符,Unicode编号范围在65536以内的占两个字节,超出范围的占四个字节,BE (Big Endian)就是先输出高位字节,再输出低位字节,这与整数的内存表示是一致的。
char本质上是一个固定占用两个字节的无符号正整数,这个正整数对应于Unicode编号,用于表示那个Unicode编号对应的字符。
由于固定占用两个字节,char只能表示Unicode编号在65536以内的字符,而不能表示超出范围的字符。
写在最后
都看到这里,保存思维导图,顺便给个赞呗!