Java中的乱码问题

引言

在写Java代码的时候,大家应该都遇到过各种乱码问题,然后开始查资料,结果原因无非是编码格式不一致所导致的乱码,解决方式也是千篇一律,统一使用UTF-8就OK了。

是的这么做乱码问题肯定可以解决,可我们似乎还不太清除是哪一步编码转化除了问题呢?

阅读本篇文章前建议先阅读 浅析计算机字符集和编码,能够对编码有一个大概的了解

Java如何处理编码问题

我们知道Java是使用了Unicode字符集,并且字符在内存中是以UTF-16编码格式来存储的,什么意思呢,就是纵然外部有各种Unicode编码格式,我Java内部使用UTF-16编码是不会变的。

以下例子证明字符在内存中是以UTF-16编码的

1
2
3
4
5
6
7
8

char c = '\u738b'; // 王的UTF-16编码是 738b

System.out.println(c); // 王

// 输出c在内存中的16进制数

System.out.println(Integer.toHexString(c)); // 738b

既然Java内部编码(内码)格式是UTF-16是不会变的,那我们读取不同的编码格式时,必然涉及到了转化过程,下面我们来看个例子

1
2
3
4
5
6

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编码在内存中存储。反过来也是类似

image.png

乱码问题出现在哪一步

现在我们再来看引言里所说提到的乱码问题,看看乱码问题一般是出现在了哪一步。上文提到,我们读取字符时,会先将内存中以UTF-16编码的字符转换成我们需要的编码格式,如Java默认就是UTF-8,那么当我们以特定的编码格式传输字节流时,接收端也必然需要以同样的编码格式去接收,不然就无法解析出正确的Unicode字符,进而也无法转换成正确的UTF-16编码在JVM内存中存储,那么必然会出现乱码问题。

总结

写本篇文章的目的是为了加深自己对Java内部编码的认识,乱码问题也是很多初学者非常痛恨和恐惧的,希望本篇文章也可以对有疑惑的同学有所帮助

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 王俊男的技术杂谈 All Rights Reserved.

访客数 : | 访问量 :