Xin*_*n69 10 java unicode intellij-idea java-18
tldr:我降级到 JDK 17 (17.0.2),现在它可以工作了......
\n我在 YT 上观看 Kody Simpson 的 Java 初学者教程 (youtube.com/watch?v=t9LP9Nt9Nco),在该教程中,男孩 Kody 打印了名为 Unicode 的疯狂符号,例如“\xe2\x98\xaf\xce\xa9\xc3” \xb8\xe1\x9a\x99",但对我来说它只是打印“?” - 一个问号。
\nchar letter = \'\\u1699\';\nSystem.out.println(letter);\nRun Code Online (Sandbox Code Playgroud)\n我尝试了 Stack Overflow 上的几乎所有解决方案,例如:
\n这些都不起作用。
\n每一个帖子都是很多年前的,比如这个,是12年前的:
\nunicode 字符在 IntelliJ IDEA 控制台中显示为问号
\n我最终删除并重新下载了 Intellij,因为我认为我弄乱了一些设置并想要重新启动,但这次我将 Project SDK 设置为旧版本,Oracle openJDK 版本 14.0.1,现在它以某种方式工作并打印了 \ '\xe1\x9a\x99\' 符号。
\n然后我意识到问题可能是 JDK 的最新版本,即版本 18,所以我下载了 JDK 17.0.2,它仍然可以工作并打印出符号 \'\xe1\x9a\x99\',所以那就是好的 :)。但是当我切换回 JDK 版本 18 时,它只打印“?” 再次。
\n这也很奇怪,因为我可以将 \xe1\x9a\x99 符号复制粘贴到编写代码区域,无论你怎么称呼它,(在 JDK 版本 18 上)
\nchar letter = \'\xe1\x9a\x99\';\nSystem.out.println(letter);\nRun Code Online (Sandbox Code Playgroud)\n但是当我按“运行”并尝试打印时......它仍然给出问号。
\n我不知道为什么会发生这种情况,我开始学习编码 2 天,所以我可能很愚蠢,或者新版本有一个错误,但我从未通过 Google 或这里找到解决方案,所以这就是为什么我发表我的第一篇 Stack Overflow 帖子。
\nsko*_*isa 15
I can replicate your problem: printing works correctly when running your code if compiled with JDK 17, and fails when running your code if compiled with JDK 18.
\nOne of the changes implemented in Java 18 was JEP 400: UTF-8 by Default. The summary for that JEP stated:
\n\n\nSpecify UTF-8 as the default charset of the standard Java APIs. With\nthis change, APIs that depend upon the default charset will behave\nconsistently across all implementations, operating systems, locales,\nand configurations.
\n
That sounds good, except one of the goals of that change was (with my emphasis added):
\n\n\nStandardize on UTF-8 throughout the standard Java APIs, except for\nconsole I/O.
\n
So I think your problem arose because you had ensured that the console\'s encoding in Intellij IDEA was UTF-8, but the PrintStream that you were using to write to that console (i.e. System.out) was not.
The Javadoc for PrintStream states (with my emphasis added):
\n\nAll characters printed by a PrintStream are converted into bytes using\nthe given encoding or charset, or the default charset if not\nspecified.
\n
Since your PrintStream was System.out, you had not specified any "encoding or charset", and were therefore using the "default charset", which was presumably not UTF-8. So to get your code to work on Java 18, you just need to ensure that your PrintStream is encoding with UTF-8. Here\'s some sample code to show the problem and the solution:
package pkg;\n\nimport java.io.FileDescriptor;\nimport java.io.FileOutputStream;\nimport java.io.PrintStream;\nimport java.nio.charset.StandardCharsets;\n\npublic class Humpty {\n\n public static void main(String[] args) throws java.io.UnsupportedEncodingException {\n\n char letter = \'\xe1\x9a\x99\';\n String charset1 = System.out.charset().displayName(); // charset() requires JDK 18\n\n System.out.println("Writing the character " + letter + " to a PrintStream with charset " + charset1); // fails\n\n PrintStream ps = new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8);\n String charset2 = ps.charset().displayName(); // charset() requires JDK 18\n ps.println("Writing the character " + letter + " to a PrintStream with charset " + charset2); // works\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n这是运行该代码时控制台中的输出:
\nC:\\Java\\jdk-18\\bin\\java.exe -javaagent:C:\\Users\\johndoe\\AppData\\Local\\JetBrains\\Toolbox\\apps\\IDEA-U\\ch-0\\221.5080.93\\lib\\idea_rt.jar=64750:C:\\Users\\johndoe\\AppData\\Local\\JetBrains\\Toolbox\\apps\\IDEA-U\\ch-0\\221.5080.93\\bin -Dfile.encoding=UTF-8 -classpath C:\\Users\\johndoe\\IdeaProjects\\HelloIntellij\\out\\production\\HelloIntellij pkg.Humpty\nWriting the character ? to a PrintStream with charset windows-1252\nWriting the character \xe1\x9a\x99 to a PrintStream with charset UTF-8\n\nProcess finished with exit code 0\nRun Code Online (Sandbox Code Playgroud)\n笔记:
\nPrintStreamJava 18 中charset()有一个新方法,名为“返回此 PrintStream 实例中使用的字符集”。上面的代码调用 charset() ,并显示对于我的机器,我的“默认字符集”是windows-1252,而不是UTF-8。更新:为了解决 Mostafa Zeinali 在下面的评论中提出的问题,可以通过调用将PrintStream使用的System.out重定向到 UTF-8 。这是示例代码:PrintStreamSystem.setOut()
String charsetOut = System.out.charset().displayName();\n if (!"UTF-8".equals(charsetOut)) {\n System.out.println("The charset for System.out is " + charsetOut + ". Changing System.out to use charset UTF-8");\n System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8));\n System.out.println("The charset for System.out is now " + System.out.charset().displayName());\n }\nRun Code Online (Sandbox Code Playgroud)\n这是该代码在我的 Windows 10 计算机上的输出:
\nThe charset for System.out is windows-1252. Changing System.out to use charset UTF-8\nThe charset for System.out is now UTF-8\nRun Code Online (Sandbox Code Playgroud)\n请注意,这System.out是一个final变量,因此您不能直接PrintStream为其分配新值。此代码无法编译,并出现错误“无法为最终变量\'out\'赋值”:
System.out = new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8); // Won\'t compile\nRun Code Online (Sandbox Code Playgroud)\n
TLDR:在 Java 18 上使用它:
\n-Dfile.encoding="UTF-8" -Dsun.stdout.encoding="UTF-8" -Dsun.stderr.encoding="UTF-8"\nRun Code Online (Sandbox Code Playgroud)\n来自JEP 400:
\n\n\nJDK 内部使用了三个与字符集相关的系统属性。它们仍然未指定且不受支持,但为了完整性而在此处记录:\nsun.stdout.encoding 和 sun.stderr.encoding \xe2\x80\x94 用于标准输出流 (System.out) 和标准错误的字符集名称流 (System.err) 和 java.io.Console API 中。sun.jnu.encoding \xe2\x80\x94 编码或解码文件名路径(而不是文件内容)时 java.nio.file 的实现所使用的字符集名称。在 macOS 上,其值为“UTF-8”;在其他平台上,它通常是默认字符集。
\n
正如您所看到的,这两个系统属性“仍然未指定且不受支持”。但他们解决了我的问题。因此,请自行承担使用它们的风险,并且不要在生产环境中使用它们。顺便说一句,我正在 Windows 10 上运行 Eclipse。
\n我认为必须有一个好方法来设置JVM在运行时的默认字符集,并且传递-Dfile.encoding =“UTF-8”并不能做到这一点是愚蠢的。正如您在 JEP 400 中所读到的:
\n\n\n如果 file.encoding 设置为“UTF-8”(即 java -Dfile.encoding=UTF-8),则默认字符集将为 UTF-8。定义此无操作值是为了保留现有命令行的行为。
\n
而这正是它“不”做的事情。传递 Dfile.encoding="UTF-8" 不会“不”保留现有命令行的行为!我认为这表明 Java 18 对 JEP 400 的实现没有做它实际应该做的事情,这首先是问题的根源。
\n