Skip to content

跨平台原理

Java 最大的特点是「一次编写,到处运行」(Write Once, Run Anywhere)。但这到底是怎么实现的?为什么 C/C++ 需要为每个平台单独编译,而 Java 不需要?

跨平台原理

┌──────────────────────────────────────────────────────────────────┐
│                         Java 跨平台原理                            │
├──────────────────────────────────────────────────────────────────┤
│    ┌──────────────┐                                              │
│    │  Hello.java  │     ←  源代码(Java)                       │
│    └──────┬───────┘                                              │
│           │  javac 编译                                          │
│           ▼                                                      │
│    ┌──────────────┐                                              │
│    │ Hello.class  │     ←  字节码(平台无关)                    │
│    └──────┬───────┘                                              │
│           │  java 运行                                           │
│           ▼                                                      │
│    ┌──────────────┐                                              │
│    │     JVM      │     ←  Java 虚拟机                          │
│    └──────┬───────┘                                              │
│     ┌─────┼─────┐                                                │
│     ▼     ▼     ▼                                                │
│  ┌────┐ ┌────┐ ┌────┐                                            │
│  │Win │ │Lin │ │Mac │     ←  不同平台的 JVM                      │
│  │JVM │ │JVM │ │JVM │                                            │
│  └────┘ └────┘ └────┘                                            │
└──────────────────────────────────────────────────────────────────┘

三层结构:字节码是统一的中间代码格式、JVM 是字节码的执行环境、平台特定 JVM 将字节码转换为本地机器码。

JVM 规范定义了统一的字节码格式,无论源代码在什么平台编写,编译后生成的字节码格式完全一致。

与 C/C++ 的对比

C/C++ 编译后生成特定 CPU 的机器码,Windows 编译的程序无法直接在 Linux 运行。

source.c → 编译器 → Windows .exe
                    → Linux .elf
                    → macOS (需重新编译)

Java 只需编译一次,生成的字节码在所有平台通用。

JVM 实现差异

每个平台有各自的 JVM 实现:Windows 有 HotSpot/Temurin,Linux 有 HotSpot/Temurin/GraalVM,macOS 有 HotSpot/Temurin。不同 JVM 实现之间可能有细微性能差异,但字节码兼容性有保证。

跨平台的限制

平台差异需处理

java
// 文件路径分隔符
String separator = File.separator;  // Windows: "\", Linux: "/"

// 换行符
String lineSeparator = System.lineSeparator();  // Windows: "\r\n", Linux: "\n"

本地方法

涉及系统底层时需要平台特定代码:

java
public native int nativeMethod();
// Windows: .dll / Linux: .so / macOS: .dylib

GC 算法差异

方面可能的差异
GC 算法G1、ZGC、Shenandoah
线程调度不同操作系统的线程模型

最佳实践

推荐做法:使用标准 API 避免平台特定调用;使用 File.separator 而非硬编码分隔符;处理换行符用 readLine()newLine()

避免做法:硬编码路径分隔符、假设文件编码(始终用 UTF-8)、使用 Runtime.exec() 执行平台特定命令。

后续可阅读:Java 程序运行机制JVM/JRE/JDK 区别Java 垃圾回收简介

基于 VitePress 构建