JAVA 的中文字符乱码问题一直很让人头疼。特别是在 WEB 应用中。网上的分析 文章和解决
方案都很多,但总是针对某些特定情况的。很多次遇到乱码问 题后, 经过极为辛苦的调试和
搜索资料后终于解决, 满以为自己已经掌握了对付这些字 符乱码怪兽的诀窍。可当过段时间,换了个应用或换了个环境,又会碰到那讨厌 的火 星文,并再次无所适从。于是下决心好好整理一下中文字符编码问题,以 方便自己记忆,也为其他程序员兄弟们提供一份参考。 首先要了解 JAVA 处理字符的原理。JAVA 使用 UNICODE 来存储字符数据,处 理字符时通常有三个步骤 - 按指定的字符编码形式,从源输入流中读取字符数据 - 以 UNICODE 编码形式将字符数据存储在内存中 - 按指定的字符编码形式,将字符数据编码并写入目的输出流中。 所以 JAVA 处理字符时总是经过了两次编码转换, 一次是从指定编码转换为 UNICODE 编码,一次是从 UNICODE 编码转换为指定编码。如果在读入时 用 错误 的形式解码字符,则内存存储的是错误的 UNICODE 字符。而从最初文件中读出的 字符数据,到最终在屏幕终端显示这些字符,期间经过了应用
程序的多次 转换。 如果中间某次字符处理,用错误的编码方式解码了从输入流读取的字符数据,或 用错误的编码方式将字符写入输出流,则下一个字符数据的接收者就会编解码 出错,从而导致最终显示乱码。 这一点,是我们分析字符编码问题以及解决问题的指导思想。 好,现在我们开始一只只的解决这些乱码怪兽。 一、在 JAVA 文件中硬编码中文字符,在 eclipse 中运行,控制台输出了乱 码。 例如,我们在 JAVA 文件中写入以下代码 String text = "大家好"; System.out.println(text); 如果我们是在 eclipse 里编译运行,可能看到的结果是类似这样的乱 码:????。那么,这是为什么呢? 我们先来看看整个字符的转换过程。 在 eclipse 窗口中输入中文字符,并保存成 UTF-8 的 JAVA 文件。这里发生了多 次字符编码转换。不过因为我们相信 eclipse 的正确性,所以我们不用分析其中 的过程,只需要相信保存下的 JAVA 文件确实是 UTF-8 格式。 2. 在 eclipse 中编译运行此 JAVA 文件。 这里有必要详细分析一下编译和运 行时的字符编码转换。
第 1 页 共 8 页
- 编译:我们用 javac 编译 JAVA 文件时,javac 不会智能到猜出你所要编 译的文件是什么编码类型的,所以它需要指定读取文件所用的编码类型。默认 javac 使用平台缺省的字符编码类型来解析 JAVA 文件。平台缺省编码是操作系 统决定的, 我们使用的是中文操作系统, 语言区域设置通常都是中国大陆, 以 所 平台缺省编码类型通常是 G
BK。这个编码类型我们可以在 JAVA 中使用 System.getProperty("file.encoding")来查 看。所以 javac 会默认使用 GBK 来解析 JAVA 文件。如果我们要改变 javac 所用的编码类型,就要加上-encoding 参数,如 javac -encoding utf-8 Test.java。 这里要另外提一下的是 eclipse 使用的是内置的编译器,并不能添加参数, 如果要为 javac 添加参数则建议使用 ANT 来编译。不过这并非出现乱码的原因, 因为 eclipse 可以为每个 JAVA 文件设置字符编码类型,而内置编译器会根据此 设置来编译 JAVA 文件。 - 运行:编译后字符数据会以 UNICODE 格式存入字节码文件中。然后 eclipse 会调用 java 命令来运行此字节码文件。因为字节码中的字符总是 UNICODE 格式,所以 java 读取字节码文件并没有编码转换过程。虚拟机读取文 件后,字符数据便以 UNICODE 格式存储在内存中了。 3. 调用 System.out.println 来输出字符。这里又发生了字符编码转换。 System.out.println 使用了 PrintStream 类来输出字符数据至控制台。 PrintStream 会使用平台缺省的编码方式来输出 字 符。我们的中文系统上缺省 方式为 GBK,所以内存中的 UNICODE 字符被转码成了 GBK 格