【语言学习】Java 编码探究 - hippowc/hippowc.github.io GitHub Wiki

计算机中的字符都是使用数字来表示的,其实计算机任何东西都是数字来表示,为了展示方便会使用16进制来展现,即使是数字“3”,在内存中或者写入到文件中也是: 0x33。16进制的一个字可以使用4位二进制来表示,也就是半个字节。

一切“字符”都必定用数字+编码表表示

由于各个国家的文字都不一样,所以希望能有一个统一的编码表,这个就是unicode。unicode规定一个字符使用两个字节表示,也就是16位,所以unicode可以表示 2^16 = 65536 中字符

C处理字符的办法:C语言没有字符串这个类型,只有char[],C把字符编码顺序放入一个字节数组,C也不管放在数组里的是什么文字,也不管那些字是按什么编码标准的。而且他的char的大小也不一定是8位数字,有时候是16位也可能,这要看具体的机器和操作系统。所以写程序的人必须要知道正在处理的char[]的内容到底是按什么编码表表示的字符串

java处理字符的办法:在JAVA里,使用String类来处理字符串,String类对象不需要指定编码表,String里的字符信息是用UNICODE编码存放的

java中的字符类型 char,占用两个字节,java的内存和文件中都是使用unicode来表示字符,unicode使用两个字节表示一个字符,可以通过这种方式查看字符在java中保存的样子(unicode)是什么

int decimal = ((int)'中');// Unicode十进制编码
String hex = Integer.toHexString(decimal); // Unicode十六进制编码

和外界交换任何信息都是以byte[]来进行,JAVA大多数的I/O类,都有以byte[]作为参数和返回值的方法,可以这样来获得一个字符char的字节数组:

byte[] b = new byte[2]; 
b[0] = (byte) ((c & 0xFF00) >> 8); 
b[1] = (byte) (c & 0xFF);

那么已经乱码的字如何再转换回来?

例子:有些老系统在request解析时使用gbk编码,而前端传递的是utf-8编码。那么到controller中拿到的就是一个错误的编码。譬如 我前端使用utf-8传递汉字 -- 中,servlet使用gbk解析,过程是这样的:

中 的unicode是:十进制20013 -- 十六进制(unicode)\u4e2d
不同系统交换信息都会使用字节数组
浏览器首先将 中,使用utf-8编码成为byte,三个字节[-28, -72, -83]
可以模拟为:

String keyword = "中";
byte[] newBytes = keyword.getBytes("utf-8"); // newBytes [-28, -72, -83]
String newKey = new String(newBytes, "gbk"); // newKey 涓�

servlet使用gbk获取编码,并转为unicode,因为gbk是两个字节,所以会把这个字解析为两个字符:涓�,unicode为:十进制:28051,65533 。其中第二个由于只有一个字节,所以使用gbk解析不出来。
然后试图修正,将错误的字符重新使用utf-8,解析出来三个字节[-28, -72, 63],无法还原为原来的值了

byte[] correctBytes = newKey.getBytes("gbk"); // correctBytes [-28, -72, 63]
String correctKey = new String(correctBytes, "utf-8"); // correctKey ??

所以由于编码使用的字节数不匹配,反向解析是会有解析不出来的情况出现,不过如果字节数正确的话,还是可以正确解析。譬如 当keyword为 中国,使用utf-8编码,是6个字节。然后错误的使用gbk解析,可以解析为三个字符:涓浗,这时候字节是没有错误,在反向解析的话,就可以获得正确的字符。

所以错误的字符,通过不同的编码格式如果获取了正确的字节流,都是可以正确解析的