如何确定 Java 是不是在 Windows 上运行

Posted

技术标签:

【中文标题】如何确定 Java 是不是在 Windows 上运行【英文标题】:How to determine that Java is running on Windows如何确定 Java 是否在 Windows 上运行 【发布时间】:2021-11-29 11:08:35 【问题描述】:

我希望确定 Java 是否在 Windows 上运行,并且看到了许多不同的建议,其中包括系统属性 os.namestartsWith / indexOf / contains / toLowerCase(Locale.ENGLISH) / @987654326 的各种排列@,或者只是File.separatorChar

我扫描了 JDK 源代码以查看是否有明确的答案(见下文)以及其他一些建议的 SO 帖子:

String os = System.getProperty("os.name" /**, "<Surely os.name is never null?>" */);
List<Boolean> isWindows = List.of(
    os.startsWith("Windows"),
    os.contains("Windows"),
    os.toLowerCase().startsWith("windows"),
    os.toLowerCase().contains("windows"),
    os.toLowerCase(Locale.ENGLISH).contains("windows"),
    os.toLowerCase(Locale.ENGLISH).startsWith("windows"),
    File.separatorChar == '\\'
);
System.out.println("os.name       ="+os);
System.out.println("os.name(UTF-8)="+Arrays.toString(os.getBytes(StandardCharsets.UTF_8)));
System.out.println("isWindows     ="+isWindows);

是否存在使用上述条件错误识别isWindows 的操作系统/语言安装的任何排列,其中真/假不一致或错误?

// For Windows I would expect all true, such as:
os.name       =Windows 10
os.name(UTF-8)=[87, 105, 110, 100, 111, 119, 115, 32, 49, 48]
isWindows     =[true, true, true, true, true, true, true]

// For non-Windows I would expect all false such as:
os.name       =Linux
os.name(UTF-8)=[76, 105, 110, 117, 120]
isWindows     =[false, false, false, false, false, false, false]

JDK 源代码示例

作为参考,这是在 Open JDK17 源代码中检测到 isWindows 的位置(来自最近的 git fetch 不是最终候选版本):

src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java

    System.getProperty("os.name").toLowerCase().startsWith("win"));
        
src/java.smartcardio/share/classes/sun/security/smartcardio/CardImpl.java
src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java    
src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java

    isWindows = System.getProperty("os.name").startsWith("Windows"))

src/java.desktop/share/classes/sun/font/FontUtilities.java

    isWindows = System.getProperty("os.name", "unknownOS").startsWith("Windows");
        
src/java.base/share/classes/java/util/zip/ZipFile.java
src/java.desktop/share/classes/sun/awt/OSInfo.java

    VM.getSavedProperty("os.name").contains("Windows")
    System.getProperty("os.name").contains("Windows")
    
src/java.desktop/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java

    boolean isWindows = osName != null && osName.contains("Windows");
        
src/java.desktop/share/classes/javax/swing/plaf/basic/BasicFileChooserUI.java

    boolean isWin32 = (File.separatorChar == '\\')
    
src/jdk.jpackage/share/classes/jdk/jpackage/internal/Platform.java
Note that I've omitted this test in case of confusion with Darwin OS:

    String os = System.getProperty("os.name").toLowerCase();
    if (os.indexOf("win") >= 0) 
        platform = Platform.WINDOWS;
    

【问题讨论】:

如果JDK的开发者不能同意,您希望我们给出什么答案?看来System.getProperty("os.name") 是众多选择中更好的选择。 File.separator 也可以用作“健全性检查” @Gilbert Le Blanc 我希望有人可以反驳其中一个布尔建议。我不能把if(System.getProperty("os.name")) 作为选择之一。 你想让jdk也支持各自系统操作系统的十种或一百种不同的方法吗?像 isAix、IsMac、Is....?基本上,我认为 os.name 已经足够了......我们可以用它来做我们想做的事情。 System.getProperty("os.name") 是要走的路。但是,请注意,它可能无法正确识别操作系统风格或版本:使用 Java 17,我在 Windows 10 桌面上获得“Windows 10”,在 Linux 服务器上获得“Linux”。到目前为止,一切都很好。使用 Java 6,我在 ArcaOS 上得到“OS/2”(这是正确的,虽然你不会区分 OS/2、eCS 和 ArcaOS),在同一个 Windows 10 桌面上我得到“Windows 8”。 【参考方案1】:

在注意到各种 cmets 和其他帖子之后,我还没有找到理由不继续使用我目前在我的代码中使用的 isWindows 检查,这只是列出的第一个测试:

boolean isWindows = System.getProperty("os.name").startsWith("Windows");

我的问题中的前六个测试似乎正确地检测到 isWindows,但不是最后一个项目 File.separatorChar == '\\'(因为在 OS/2 上也是如此)。

请注意,在土耳其语中,“I”的小写值不等于“i”。试试:

"I".toLowerCase(Locale.forLanguageTag("TR")).equals("i") // char:305
"i".toUpperCase(Locale.forLanguageTag("TR")).equals("I") // char:304

也许这解释了为什么一些开发人员使用.toLowerCase(Locale.ENGLISH),但除非os.name 属性在土耳其语安装中为大写,否则任何测试结果都不会发生任何变化。

感谢所有建议。

【讨论】:

以上是关于如何确定 Java 是不是在 Windows 上运行的主要内容,如果未能解决你的问题,请参考以下文章

跨越不确定风险,华为云 SRE 探索云上运维的确定性答案

更改脚本以在特定工作表上运行会引发TypeError

给定一个线程 id,如何确定它是不是仍在 Windows 上运行

如何检测 x64 Windows 上是不是安装了 32 位 Java,仅查看文件系统和注册表?

如何以编程方式确定 Windows 中是不是安装了 Mono 64 位以及安装在何处?

如何以编程方式确定 Windows 任务栏是不是隐藏?