Console 是 Java 里唯一内置的“不回显”输入方式,但它只在真正的终端里存在。这篇用伪终端和管道对比运行,量出它在三个 JDK 版本里什么时候是 null、密码是否真的不回显、EOF 的行为,以及字符集的坑。
[JDK 17] 管道:System.console() == null;System.in.available() 可读 = true;jdk.console = null [JDK 17] 伪终端:System.console() != null(java.io.Console);(无 isTerminal 方法);System.in.available() 可读 = true;jdk.console = null [JDK 21] 管道:System.console() == null;System.in.available() 可读 = true;jdk.console = null [JDK 21] 伪终端:System.console() != null(java.io.ProxyingConsole);(无 isTerminal 方法);System.in.available() 可读 = true;jdk.console = null [JDK 27] 管道:System.console() == null;System.in.available() 可读 = true;jdk.console = null [JDK 27] 伪终端:System.console() != null(java.io.ProxyingConsole);isTerminal() = true;System.in.available() 可读 = true;jdk.console = null [JDK 27] 管道 + -Djdk.console=java.base:System.console() == null;System.in.available() 可读 = true;jdk.console = java.base
[JDK 17] readLine + readPassword 的终端内容:姓名: <<发送>>alice⏎密码: <<发送>>⏎RES 读到姓名 alice,密码长度 10,密码首字符 S⏎RES 用完后 Arrays.fill 清零,pw[0] = 0⏎
密码 Secret123! 出现在终端输出里 = False;姓名 alice 的回显在终端里 = True
[JDK 17] Scanner:密码(用 Scanner 读): <<发送>>Secret123!⏎RES Scanner 读到长度 10⏎ → 密码 Secret123! 出现在终端输出里 = True(终端回显)
[JDK 21] readLine + readPassword 的终端内容:姓名: <<发送>>alice⏎密码: <<发送>>⏎RES 读到姓名 alice,密码长度 10,密码首字符 S⏎RES 用完后 Arrays.fill 清零,pw[0] = 0⏎
密码 Secret123! 出现在终端输出里 = False;姓名 alice 的回显在终端里 = True
[JDK 21] Scanner:密码(用 Scanner 读): <<发送>>Secret123!⏎RES Scanner 读到长度 10⏎ → 密码 Secret123! 出现在终端输出里 = True(终端回显)
[JDK 27] readLine + readPassword 的终端内容:姓名: <<发送>>alice⏎密码: <<发送>>⏎RES 读到姓名 alice,密码长度 10,密码首字符 S⏎RES 用完后 Arrays.fill 清零,pw[0] = 0⏎
密码 Secret123! 出现在终端输出里 = False;姓名 alice 的回显在终端里 = True
[JDK 27] Scanner:密码(用 Scanner 读): <<发送>>Secret123!⏎RES Scanner 读到长度 10⏎ → 密码 Secret123! 出现在终端输出里 = True(终端回显)[JDK 21] Ctrl-D:密码: <<发送>>⏎RES 输入 Ctrl-D 之后 readPassword 返回 null⏎再读一行: <<发送>>^DRES 之后 readLine 返回 null⏎ [JDK 27] Ctrl-D:密码: <<发送>>⏎RES 输入 Ctrl-D 之后 readPassword 返回 null⏎再读一行: <<发送>>^DRES 之后 readLine 返回 null⏎ [JDK 17] 伪终端,默认环境:Console.charset() = UTF-8;Charset.defaultCharset() = UTF-8;stdout.encoding = null;native.encoding = UTF-8 [JDK 21] 伪终端,默认环境:Console.charset() = UTF-8;Charset.defaultCharset() = UTF-8;stdout.encoding = UTF-8;native.encoding = UTF-8 [JDK 27] 伪终端,默认环境:Console.charset() = UTF-8;Charset.defaultCharset() = UTF-8;stdout.encoding = UTF-8;native.encoding = UTF-8 [JDK 21] 伪终端,LC_ALL=C:Console.charset() = US-ASCII;Charset.defaultCharset() = UTF-8;stdout.encoding = US-ASCII;native.encoding = US-ASCII [JDK 21] 管道:Console.charset() = (无 charset 方法);Charset.defaultCharset() = UTF-8;stdout.encoding = UTF-8;native.encoding = UTF-8