在 JDK 21 / macOS 上实测 ProcessHandle:info() 能读到命令与 CPU 时间但只有 454 / 742 个进程有 command;descendants() 比 children() 多孙进程,只杀父进程后 4 个后代全部存活并改挂到 pid 1;onExit() 对非子进程也有效,延迟约 3–13 ms;destroy() 返回 true 但忽略 SIGTERM 的进程仍然活着,destroyForcibly 得到退出码 137。
在 JDK 21 / macOS 上实测 ProcessBuilder:拼接 sh -c 会执行注入的命令而数组参数不会;Runtime.exec(String) 不识别引号;不读输出时子进程写到 70000 字节就阻塞(管道约 64 KiB),stderr 同样;pb.start() 用 Java 进程的 PATH 查找可执行文件而 sh -c 用子进程的 PATH;启动失败的错误码 2 / 13 / 7。
在 JDK 21 上实测 System.Logger:默认后端是 java.util.logging(TRACE / DEBUG 不输出,ERROR 显示为 SEVERE);Supplier 在级别禁用时不求值而 expensive() 直接调用求值 1000 次;占位符是 MessageFormat 的 {0} 而不是 %s;禁用时字符串拼接 10.8 ns 而 Supplier 约 2 ns;自定义 LoggerFinder 能收到 JDK 的 Runtime.exit 日志。
用伪终端在 JDK 17 / 21 / 27 上实测 Console:管道里 System.console() 为 null,伪终端里非 null(JDK 27 多了 isTerminal());readPassword 不回显并返回可清零的 char[],而 Scanner 与 readLine 会回显;Ctrl-D 让 readPassword 返回 null;LC_ALL=C 时 Console.charset() 是 US-ASCII 而 defaultCharset() 仍是 UTF-8。
在 macOS / JDK 21 上实测 java.util.prefs:userRoot 是 MacOSXPreferences,存在 com.apple.java.util.prefs.plist;put 不 flush 也立刻持久(kill -9 后仍读到);key 80 / value 8192 / 节点名 80 的上限;getInt 解析失败返回默认值;外部进程的修改能读到但监听器不通知;systemRoot 无权限写入。
在 JDK 21 上实测 EdDSA:Ed25519 公钥 44 / 私钥 48 / 签名 64 字节;同一消息签 20 次只有 1 个不同的签名(ECDSA 是 20 个);Java 签出的签名与 RFC 8032 测试向量逐字节相同,并与 OpenSSL 互通;篡改、截断、S ≥ L 都被拒绝;JDK 21 的 SunEC 上 Ed25519 签名 422 µs,比 ECDSA P-256(120 µs)慢约 3.5 倍。
在 JDK 21 上实测 X25519:RFC 7748 的测试向量公钥与共享密钥逐字节相同;getU() 是大端 BigInteger 而编码是小端;私钥有 5 位被 clamp 而不起作用;小阶点公钥一律抛 InvalidKeyException;与 OpenSSL 互通;协商 97 µs,比 ECDH P-256(552 µs)快约 5.7 倍。
在 JDK 21 上实测 RSASSA-PSS:必须 setParameter;盐 0 时签名确定、盐 20/32 时每次不同;RSA 2048 的最大盐是 222(SHA-256),超出时抛“Key is too short”;验证者必须知道盐长度;RSASSA-PSS 类型的密钥限定摘要与最小盐;与 OpenSSL 互通;PSS 与 PKCS#1 v1.5 的签名耗时相同(872 µs)。
在 JDK 21 上实测 CipherInputStream:GCM 被篡改或截断时一个明文字节都不交出并抛 IOException ← AEADBadTagException;CBC 无认证,中间篡改完全不被发现,NoPadding 在块边界截断悄悄少 16 字节;close() 不做验证;CipherOutputStream 忘记 close 得到 992 / 1016 字节的残缺文件;-Xmx128m 下 GCM 解密 40 MiB 起 OutOfMemoryError。
在 JDK 17 / 21 / 27 上实测 KeyPairGenerator:不 initialize 时 RSA 默认从 2048 位升到 3072 位、EC 从 256 升到 384;RSA 512–16384 位都可生成(1023 与 4097 也可以)、公钥指数必须是奇数;EC 只支持 P-256 / 384 / 521;RSA 2048 生成耗时 28–294 ms 波动 4.5 倍而 EC 几乎固定;SHA1PRNG + setSeed 可重现密钥;输出可被 OpenSSL 直接读取。
用 Java 对真实站点(github.com、wikipedia.org、example.com)做证书透明度验证:解析内嵌 SCT,重建预证书 TBS 并用日志公钥验证 5 个 SCT 的签名,向 Google Argon2026h2 日志取 STH 与审计路径验证 Merkle 包含证明(根与 STH 相同,条目逐字节相同);JDK 自己的 TLS 握手不检查 SCT。
在 JDK 21 上用本地 CA 与 openssl s_server 实测证书主机名验证:默认的 SSLSocket 对 15 种证书 / 主机名组合全部握手成功(不检查主机名),加上 HTTPS 端点标识或使用 HttpsURLConnection 只成功 9 种、HttpClient 8 种;SAN 优先于 CN、通配符只匹配一级、IP 必须用 IP 类型的 SAN;一行 setHostnameVerifier((h, s) -> true) 就让检查失效。