Bytecode and Platform Independence
A movie released across India is often dubbed into many languages, one version for each. Subtitles work differently: there's one film, and each viewer reads it in a way they understand. Java chose the subtitle approach. You compile once into bytecode, a single format for every computer, and the JVM on each machine handles the rest.
What Bytecode Is
Bytecode is the instruction set of the Java Virtual Machine. Each instruction is one byte long (that's where the name comes from), sometimes followed by a few bytes of data. There are about 200 of them, and they are simple: push a number, add two values, call a method, return.
Bytecode is:
- Not machine code. No real processor runs it directly.
- Not source code. You can't read it the way you read Java.
- The same everywhere. A
.classfile compiled on Windows is byte-for-byte identical to one compiled from the same source on a Mac.
Look at It with javap
Take this small method that works out GST:
public class Gst {
static int gst(int price) {
return price * 18 / 100;
}
public static void main(String[] args) {
System.out.println("GST on Rs. 500: Rs. " + gst(500));
}
}GST on Rs. 500: Rs. 90Compile it, then use javap -c from the JDK to print the bytecode:
javac Gst.java
javap -c GstThe part for the gst method looks like this:
static int gst(int);
Code:
0: iload_0
1: bipush 18
3: imul
4: bipush 100
6: idiv
7: ireturnHow to read it
iload_0puts the first parameter,price, on the JVM's operand stack.bipush 18pushes the number 18.imultakes the top two values, multiplies them, and pushes the result.bipush 100andidivdivide that result by 100.ireturnreturns theinton top of the stack.
The numbers on the left (0, 1, 3, 4, 6, 7) are byte positions in the method's code. bipush takes two bytes, so the next instruction starts two bytes later. The i at the start of many instructions means int.
Try it yourself: change gst to use price * 0.18 and return a double. Compile, run javap -c Gst again, and spot the instructions that start with d instead of i.
What's Inside a .class File
A .class file isn't just bytecode. It also stores everything the JVM needs to know about the class:
| Part | What it holds |
|---|---|
| Magic number | The first four bytes are always CA FE BA BE, so the JVM can recognize a class file |
| Version | The class file version, which says which Java version compiled it |
| Constant pool | Every name, string and number the class uses, such as "GST on Rs. 500: Rs. " and java/io/PrintStream |
| Class information | The class name, its parent class and its interfaces |
| Fields and methods | Their names, types and modifiers, plus the bytecode of each method |
Run javap -v Gst to see all of it, including the constant pool.
Class File Versions
Every Java release has its own class file version number:
| Java version | Class file version |
|---|---|
| Java 8 | 52 |
| Java 11 | 55 |
| Java 17 | 61 |
| Java 21 | 65 |
| Java 25 | 69 |
A JVM can run class files of its own version or older, but not newer ones. Compile with Java 25 and run on a Java 17 JVM, and you get this real error:
Error: LinkageError occurred while loading main class Gst
java.lang.UnsupportedClassVersionError: Gst has been compiled by a more recent version of the Java Runtime (class file version 69.0), this version of the Java Runtime only recognizes class file versions up to 61.0Read it as: "compiled by Java 25 (69), but this is Java 17 (61)".
The Same Numbers Everywhere
Part of platform independence is that Java's basic types have fixed sizes on every computer. In C, an int can be 16 or 32 bits depending on the machine; in Java it's always 32.
public class Sizes {
public static void main(String[] args) {
System.out.println("int: " + Integer.SIZE + " bits");
System.out.println("long: " + Long.SIZE + " bits");
System.out.println("char: " + Character.SIZE + " bits");
System.out.println("double: " + Double.SIZE + " bits");
System.out.println("Max int: " + Integer.MAX_VALUE);
}
}int: 32 bits
long: 64 bits
char: 16 bits
double: 64 bits
Max int: 2147483647This output is identical on Windows, macOS, Linux, a server or a Raspberry Pi. The lesson "Data Types in Java" covers each type in detail.
Where Platform Independence Stops
Bytecode is portable, but your program can still depend on the operating system if you write it that way:
| OS-dependent thing | Portable way |
|---|---|
File paths like C:\data\bill.txt | Path.of("data", "bill.txt") |
Line endings (\r\n on Windows, \n elsewhere) | System.lineSeparator(), or println |
Running OS commands such as dir or ls | Use Java's file APIs instead |
Native libraries (.dll, .so, .dylib) | Ship one per platform, or avoid them |
Common Mistakes
Thinking bytecode is slow because it's "interpreted". The JVM interprets it only at first; the JIT compiler turns busy code into machine code. The next lesson explains how.
Running newer class files on an older JVM. Check both versions: javac -version where you build and java -version where you run.
Thinking javap shows your source code. It shows the bytecode the compiler produced. Tools called decompilers try to rebuild source from bytecode, but javap doesn't.
Interview Corner
What is bytecode?
Bytecode is the instruction set of the JVM, produced by javac and stored in .class files. It isn't machine code for any real processor; the JVM interprets it and its JIT compiler turns frequently run parts into machine code.
How does Java achieve platform independence?
javac compiles source code into bytecode instead of machine code for one processor. Every platform has its own JVM that runs this same bytecode, and Java's primitive types have fixed sizes everywhere, so one .class file behaves the same on every platform.
What causes UnsupportedClassVersionError?
Running a class file on a JVM older than the compiler that produced it, for example a class compiled by Java 25 (version 69) on Java 17 (which supports up to 61). Fix it by running a newer JVM or compiling with --release for the older one.
Practice
- Easy: Compile
Gst.javaand runjavap -v Gst. Find the line that saysmajor version. What number is it, and which Java version does it mean? - Harder: Write a method
static int discount(int price)that returnsprice - price / 10. Predict the bytecode instructions before you look atjavap -c.
Key Takeaways
Was this tutorial helpful?