Skip to content

面试被问"Java 为什么跨平台",我背过八股:编译成字节码,JVM 解释执行。但被追问一句"机器码和字节码到底什么区别,C 编译出来的 exe 为什么换台机器就跑不了"——又卡住了。这篇把三层执行模型讲透:源码、字节码、机器码各是什么,谁在执行,为什么要有中间层。

一、解决什么问题:代码是怎么"活"起来的

你写的代码是给人看的,但CPU 只认二进制。从"人看的代码"到"CPU 执行的指令",中间隔着一层甚至两层翻译。搞清楚这个过程,很多"为什么"就通了:

  • 为什么 Java 能跨平台、C 不能
  • 为什么 Java 要预热(JIT)
  • .class 文件开头的 CAFEBABE 是什么

二、三层模型:源码 → 字节码 → 机器码

C 路径(机器码)vs Java 路径(字节码)

机器码(Machine Code):CPU 的母语

CPU 直接执行的二进制指令01001110...),由硬件架构决定:

  • 绑定架构:x86 的机器码在 ARM 上跑不了(指令集不同)
  • 不可读:基本无法人工阅读,反汇编也是难懂的汇编
  • 编译期定死gcc 编译出 .exe 的那一秒,指令就定死了

C/C++ 走这条路:源码 → 编译 → 机器码 → 直接交给 CPU。

字节码(Bytecode):虚拟机的中间语

面向虚拟机的指令集,不绑任何硬件:

  • 平台无关:Java 字节码在 Windows、Linux、macOS 的 JVM 上都能跑
  • 可反编译javap 能看(iconst_1iadd 这种"JVM 汇编")
  • 运行时才定:真正变成机器码是运行时(JIT)的事

Java 走这条路:源码 → 编译 → 字节码 → JVM(翻译)→ CPU。

三、核心区别

维度机器码 Machine Code字节码 Bytecode
谁执行CPU(硬件)虚拟机(软件)
平台绑定绑死 CPU 架构不绑平台
可读性纯二进制,不可读可反编译(javap)
生成时机编译期生成,永不变编译期生成,运行时才翻译成机器码
换平台重新编译换个 JVM 就行
例子01001110 10010110...iconst_1 / iadd

一句话:机器码是给硬件看的,字节码是给虚拟机看的;字节码最后也要变成机器码才能跑,但"变"的时机和地点(运行时、各平台的 JVM 里)就是跨平台的秘密。

四、.class 文件长什么样:CAFEBABE

所有 Java 字节码文件开头固定 4 个字节 CAFEBABE(魔数),JVM 靠它识别"这是不是合法的 .class"。实测看一眼编译出来的 Hello.class 文件头:

$ xxd Hello.class
00000000: cafe babe 0000 0041 001b ...   ← cafe babe 就是魔数

魔数后面的字节是版本号、常量池……整个文件就是一套 JVM 能读懂的"指令+数据"。

五、字节码怎么变成机器码:解释器 vs JIT vs AOT

字节码自己不会跑,得翻译成机器码,有三种方式:

方式做法特点
解释执行逐条翻译逐条执行启动快,每条都翻译,慢
JIT 编译热点代码整体编译成机器码缓存越跑越快(HotSpot 默认,详见《JVM 是什么》)
AOT 编译提前编译成机器码(GraalVM 原生镜像)启动极快,但失去部分动态性

实测 JIT 差距(1 亿次循环,同一个 JVM):

默认(JIT 生效):25 ms
-Xint(纯解释): 426 ms   ← 差 17 倍

六、各语言都在用"字节码"

不是只有 Java 有字节码——只要想跨平台,都会搞一个中间层:

语言字节码虚拟机
Java / Kotlin.class(CAFEBABE)JVM
Python.pycCPython 解释器
C#.NET ILCLR
JavaScript → WebAssembly.wasm浏览器(现代浏览器)

小结

  • 机器码:CPU 母语,二进制、绑平台、编译期定死
  • 字节码:虚拟机中间语,平台无关、可反编译、运行时才翻译
  • 跨平台本质:字节码 + 各平台的虚拟机 = 处处可跑
  • CAFEBABE:.class 文件的魔数,JVM 认它的身份证
  • 三种翻译:解释器(慢)、JIT(越跑越快)、AOT(启动快)

JVM 怎么用这套机制跑起 Java 程序,看《JVM 是什么:跨平台原理与整体架构》;字节码最终在内存里怎么被管理,看《JVM 内存模型与垃圾回收》。

验证说明:xxd 查看 Hello.class 文件头 cafe babe 魔数、javap -c 反编译字节码指令(iconst_1/iadd)、JIT 对比(默认 25ms vs -Xint 426ms)全部本地实测