Java中的乱码问题
引言
在写Java代码的时候,大家应该都遇到过各种乱码问题,然后开始查资料,结果原因无非是编码格式不一致所导致的乱码,解决方式也是千篇一律,统一使用UTF-8
就OK了。
是的这么做乱码问题肯定可以解决,可我们似乎还不太清除是哪一步编码转化除了问题呢?
阅读本篇文章前建议先阅读 浅析计算机字符集和编码,能够对编码有一个大概的了解
Java如何处理编码问题
我们知道Java是使用了Unicode
字符集,并且字符在内存中是以UTF-16
编码格式来存储的,什么意思呢,就是纵然外部有各种Unicode
编码格式,我Java内部使用UTF-16
编码是不会变的。
以下例子证明字符在内存中是以UTF-16
编码的
char c = '\u738b'; // 王的UTF-16编码是 738b
System.out.println(c); // 王
// 输出c在内存中的16进制数
System.out.println(Integer.toHexString(c)); // 738b
既然Java内部编码(内码)格式是UTF-16
是不会变的,那我们读取不同的编码格式时,必然涉及到了转化过程,下面我们来看个例子
String s = "王";
byte [] bytes = s.getBytes();
System.out.println(bytes.length); // 输出 3
上面的例子,可以看到相同的字符王
,存储在char
中两个字节,转换成字节流输出后变成占用3个字节了。问题来了,这个过程发生了什么了?
上面代码中getBytes()
方法其实我们使用了默认的UTF-8
编码格式,其实完整的写法应该是byte [] bytes = s.getBytes("UTF-8")
,这里其实就是获取了UTF-8
编码格式的字节流。那么这里又是如何获取到字节王
的UTF-8
编码的呢?
看下图,可知任何编码转换都会经由Unicode
字符集中转。例如我们读取UTF-8
编码的字符,会先转化成Unicode
字符,然后再转成UTF-16
编码在内存中存储。反过来也是类似
乱码问题出现在哪一步
现在我们再来看引言里所说提到的乱码问题,看看乱码问题一般是出现在了哪一步。上文提到,我们读取字符时,会先将内存中以UTF-16
编码的字符转换成我们需要的编码格式,如Java默认就是UTF-8
,那么当我们以特定的编码格式传输字节流时,接收端也必然需要以同样的编码格式去接收,不然就无法解析出正确的Unicode
字符,进而也无法转换成正确的UTF-16
编码在JVM内存中存储,那么必然会出现乱码问题。
总结
写本篇文章的目的是为了加深自己对Java内部编码的认识,乱码问题也是很多初学者非常痛恨和恐惧的,希望本篇文章也可以对有疑惑的同学有所帮助