Bytecode

Bytecode is the intermediate instruction set produced by the Java compiler (javac) when it compiles .java source into .class files. The JVM reads these instructions and either interprets them or JIT-compiles them to native machine code at runtime.

Why an intermediate format?

Bytecode is the foundation of Java's "write once, run anywhere" promise. The compiler produces one platform-neutral .class file; every JVM — on Windows, macOS, Linux, ARM, x86 — knows how to execute it. No recompilation is needed to port between platforms.

Inspecting bytecode

javac Hello.java
javap -c Hello.class
Compiled from "Hello.java"
public class Hello {
  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #7   // Field java/lang/System.out
       3: ldc           #13  // String Hello, world!
       5: invokevirtual #15  // Method PrintStream.println
       8: return
}

Other JVM languages emit bytecode too

Kotlin, Scala, Clojure, Groovy and Jython all compile to JVM bytecode. That is why they run on the JVM and can call Java libraries directly.

Bytecode != machine code

Bytecode is an abstract, stack-based instruction set the JVM interprets or JIT-compiles. Native machine code is the CPU-specific instruction stream that actually runs on the hardware. The JIT compiler bridges the two at runtime, compiling hot methods to fast native code while leaving rarely-executed code interpreted.