From source to bytecode

JVM · lesson 2 of 34 · 3 min read

Open the class file javac produced and meet the little stack machine underneath Java.

Open this lesson in the learning hub

Key points

  • javac checks types and writes a .class file. It optimises almost nothing - that job belongs to the JVM at runtime.
  • Bytecode is a stack machine. Push the operands, run one instruction, it pops them and pushes the result.
  • There are around 200 opcodes and most are dull: iload, iadd, invokevirtual, areturn.
  • javap -c disassembles any class file. It is the fastest way to answer "what did the compiler actually do here".
  • Every class file starts with the magic number 0xCAFEBABE and a version. Class file 65 means Java 21.
  • Run a newer class file on an older JVM and you get UnsupportedClassVersionError. Bytecode is forward compatible, not backward.

Example

# compile, then look at what javac actually produced
javac Adder.java

javap -c Adder
#   int add(int, int);
#     0: iload_1          // push the first argument
#     1: iload_2          // push the second argument
#     2: iadd             // pop both, push the sum
#     3: ireturn          // return the top of the stack

# the header: magic number, class file version, constant pool
javap -v Adder | head -20

Bytecode is a small stack machine, and javap -c shows it to you.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the JVM course, and every lesson in it is listed on the JVM contents page.