最近我正在尝试把JDK8升级到JDK21。
我新建了一个Sping Boot 3.3.0的项目,SDK设置为Oracle OpenJDK 21.0.2,并在main方法中写了一个简单的 System.out.println(“你好,世界”) ,运行后得到一串乱码。按照JDK8的经验,我检查了IDEA的相关配置:
1. File->Settings有关encoding的选项已经是UTF-8
2. Help->Edit Custom VM Options中已经添加了-Dfile.encoding=UTF-8
都正确,咋还是报错呢?我在网上找了好久,终于找到一个靠谱的解决办法,在Run->Edit Configurations里,增加VM Options: -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8,再次运行,问题解决。
作为一个严谨的Java程序员,知其然,也要知其所以然,在经过一番研究后得出如下结论。先说解决方案(需要提前说明的是,为了兼容既有项目,我的IDEA还是用JDK8启动的):
1. JDK17及以前:在Custom VM Options中增加-Dfile.encoding=UTF-8
2. JDK18:在Run->Edit Configurations中增加VM Options: -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
3. JDK19到JDK21:在Run->Edit Configurations中增加VM Options: -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8
再说原因:
1. 乱码
众所周知,计算机世界是构建在二进制也就是0和1之上的。我们能读懂的字符也是按照既定规则用一连串的0和1来表示的,这个既定规则就是字符编码。字符编码有很多,我们常见的有ASCII、GBK、GB2312和UTF-8等。按照这些规则把字符转换为0和1的过程叫编码,反之叫解码。如果我们使用某种规则编码,却使用另一种规则解码时,可能会出现找不到或找错对应字符的情况,就会显示一些我们读不懂的字符,也就是乱码。
2. 流程及编码设置
既然乱码是由于编解码所用规则不一致导致的,那就需要统一编码。下图是从编写代码到运行的大概流程:
其中涉及编解码的地方:
① 编写代码并存储到.java文件,这里的字符编码需要在开发工具里设置,在IDEA里边就是File ->Settings下有关encoding的选项;
② Java编译器读取.java文件,可以通过javac -encoding UTF-8来设置字符编码,如果不设置,就使用操作系统的。如果用Gradle等构建工具,虽然有设置方法,但一般用不到;
③ Java编译完成后,生成.class文件,这里的编码不可设置,按Java虚拟机规范只能是UTF-8;
④ 运行程序,.class文件中的字符加载到内存,程序读取内存中的数据给标准输出流并解码成字符,输出到控制台(大概是这样)。这里如果不指定字符编码,也是使用操作系统的。如何指定需要分情况说明。
3. 如何设定标准输出流的字符编码
根据JEP 400里的描述,JDK17及以前,标准输出流使用默认字符编码,而默认字符编码是在Java运行时启动时从操作系统获取的。检查默认字符编码的方法:
java -XshowSettings:properties -version 2>&1 | grep file.encoding
所以,JDK17及以前通过设置file.encoding就可以。
到了JDK18,默认字符编码指定为UTF-8。我们虽然可以通过file.encoding来设置,但只能设置成COMPAT或者UTF-8,其他的可能没效果。如果设置成COMPAT,就像JDK17那样,从操作系统获取字符编码。
有意思的是JDK18中System.out和System.err却不用默认编码了,修改file.encoding对这俩没有效果,只能通过sun.stdout.encoding和sun.stderr.encoding来设置。虽然JEP400中说这两个属性依然是未指定和不被支持的(unspecified and unsupported),但这俩确实有效,我也没找到其他方法。
到了JDK19,新增了stdout.encoding和stderr.encoding两个属性,专门用来指定System.out和System.err的字符编码,如果不指定,还是按操作系统的来。
由于篇幅和时间限制,具体调试过程并未写出,有兴趣的人可以把几个关键版本的JDK都安装好,试着调试一下。
参考内容
[1] 网上类似问题解决办法「链接」
[3] Chapter�4.燭he class File Format
标签:编码,UTF,encoding,IDEA,乱码,设置,字符,控制台 From: https://blog.csdn.net/zhilan_note/article/details/139629768