相同的是字节码
.class 遵循 JVM 规范,不直接保存 Windows、macOS 或 Linux 的机器指令。平台差异主要由各自的 JVM 实现承接。
把同一个 PlatformProbe.class 交给不同平台的 JVM,再逐项加入版本、JNI 与路径条件,观察“跨平台”在哪一步成立、又会在哪一步失效。
先做预测:如果 .class 文件完全相同,只更换目标操作系统,它一定能运行吗?答案取决于 JVM 版本,以及程序是否越过了 Java 世界与本机环境的边界。
System.out.println(System.getProperty("os.name"));
文本
javac --release 17 PlatformProbe.java
已编译
目标 JVM 足够新,且没有不匹配的平台依赖。
字节码指纹与编译目标保持不变,只替换平台 JVM;依赖条件会按各平台重新判定。
| 目标平台 | 收到的字节码 | 平台 JVM 的工作 | 最终结果 |
|---|
.class 遵循 JVM 规范,不直接保存 Windows、macOS 或 Linux 的机器指令。平台差异主要由各自的 JVM 实现承接。
较新的 JVM 通常能运行较旧的 class;较旧 JVM 读到更新的 class 版本,会在程序启动前抛出 UnsupportedClassVersionError。
JNI 库、固定绝对路径、外部命令、默认编码与文件权限都可能重新引入平台差异。“一次编译,到处运行”是一组条件,而不是无条件承诺。
默认不能。Java 21 对应 class 主版本 65,而 Java 17 JVM 最高识别 61。可用支持的编译器通过 --release 17 生成较低目标版本,但代码也必须遵守 Java 17 的 API 与语言边界。
不能。class 可以相同,但 JNI 背后的原生库必须分别编译为 Windows 的 .dll、macOS 的 .dylib 或 Linux 的 .so,并匹配 CPU 架构。
相对路径减少了路径语法和盘符绑定,但仍取决于当前工作目录、文件是否部署、大小写规则与权限。它提高可移植性,不等于资源必然存在。