java乱码问题分析
- 问题描述
- 原因分析:
- 解决方案:
- 要求
- 实例
- 补充:
- 常见的两种字符集及其代码:
- Windows系统下查看默认字符集
- Windows系统切换命令行字符集
- 总结
问题描述
两种情况:
- 使用javac命令编译的时候报错,例如:
- 编译的时候没报错,但在使用java命令运行class文件时出现乱码,例如:
原因分析:
一个Java源代码到输出的过程如下所示:
在解码、编码和显示的时候都会使用到字符集。
- 通常,在使用javac命令不加任何选项时,javac命令会使用当前系统默认的字符集将.java源文件解码,然后再把解码之后的内容再翻译然后以当前系统默认的字符集编码成.class字节码文件,例如windows系统(通常是GBK)下:
- 如果使用javac命令时,添加了-encoding <字符集> 选项,那么会使用这个指定的字符集将.java解码,然后翻译,然后还是会根据当前系统默认的字符集编码成.class字节码文件,例如在windows系统下使用javac -encoding utf-8命令编译时:
- 这就是为什么.java文件字符集为utf-8,使用了javac -encoding utf-8命令,命令行的字符集也是utf-8时还会出现乱码,例如:
- 这是因为虽然javac命令在解码时是根据utf-8解码的,但是编码时还是使用系统默认的GBK,所以使用utf-8字符集的命令行运行这个以GBK编码的.class文件,还是会出现乱码。
- 在命令行使用java命令执行.class字节码文件的时候,命令行会根据当前命令行的字符集(通常和系统默认字符集相同)把结果显示出来。
所以在上面遇到的问题,如果这时候把命令行的字符集换成GBK,执行这个.class文件就能正确显示了,如下图:
综上,出现乱码或者编译时报错说有不可映射的字符,那么就是.java源文件与javac命令解码时使用的字符集不同或者是javac命令编码时使用的字符集(也就是生成的.class字节码文件的字符集)与命令行的字符集不同。
解决方案:
要求
不出现乱码需要满足两点要求:
- 编译时,.java源文件使用的字符集与使用javac命令时使用的字符集相同。也就是说如果系统默认的字符集与.java源文件的字符集不同,就必须要使用-encoding指定字符集;如果系统默认字符集与.java文件相同直接使用javac即可。
- 执行时,.class字节码文件(.class字节码文件的字符集与它生成时的系统默认字符集相同)使用的字符集与命令行使用的字符集相同。也就是说一般情况下,由于命令行的字符集通常与系统的字符集相同,所以在同一个计算机上编译(需要满足上述要求1)得到的.class文件是直接能执行并且不会出现乱码的;如果是在一台计算机上编译(满足上述要求1),然后把编译得到的.class文件拿到另一个计算机上执行,那么可能因为两台计算机的系统默认字符集不同而出现乱码,这时候如果需要执行这个.class文件,就必须把命令行的字符集改成与.class文件相同的字符集,例如“原因分析”部分使用的例子。
实例
↑由于系统字符集是GBK,与.java文件的utf-8不同,所以在使用javac命令时使用-encoding utf-8指定使用utf-8解码。然后由于命令行的字符集默认是与系统字符集相同的,所以使用java命令执行时,直接能正确显示。
补充:
常见的两种字符集及其代码:
字符集 | 代码 |
GBK | 936 |
utf-8 | 65001 |
Windows系统下查看默认字符集
在命令行中使用以下命令即可:
chcp
Windows系统切换命令行字符集
在命令行中使用以下命令即可切换到指定字符集:
chcp <字符集代码>
总结
如果只是在一台计算机上编译+执行,那么使用javac -encoding <.java源文件的字符集> 命令编译,直接java命令执行,一般都不会出现乱码。如果出现乱码了就得根据编译和执行这两个方面去检查是否符合要求。
上述只是我的个人理解,如有问题还请指出,非常感谢!