CLASS File Documentation
Summary
A CLASS file is compiled Java bytecode, the output the Java compiler (javac) produces from a .java source file. It is not meant to be read directly: it is loaded and run by the Java Virtual Machine (JVM), so you need Java installed. Every .class begins with the magic number CA FE BA BE. Real programs ship as a JAR (a ZIP of many .class files), and to recover source you must decompile it. Its MIME type is application/java-vm.
Technical details
| Feature | Value |
|---|---|
| Full name | Java Bytecode Class File |
| File extension | .class |
| MIME type | application/java-vm |
| Format type | Compiled Java bytecode (binary) |
| Developer | Sun Microsystems (now Oracle); part of the Java Platform |
| Introduced | 1995–1996 (Java 1.0) |
| Standard | The Java Virtual Machine Specification, Chapter 4 |
| Open standard | Yes — the class file format is publicly specified |
| Byte order | Big-endian |
| Magic number | CA FE BA BE (offset 0) |
| Version stamp | 2-byte minor + 2-byte major after the magic |
| Major 52 / 61 / 65 | Java 8 / Java 17 / Java 21 |
| Executed by | The Java Virtual Machine (JVM) |
| Run with | java MyClass (needs a JDK/JRE) |
| Read source | Decompile (JD-GUI, CFR) or disassemble (javap -c) |
| Typical packaging | Many .class files inside a .jar (a ZIP) |
| Related extensions | .java, .jar, .war, .jmod, .dex |
| Specification | docs.oracle.com/javase/specs/jvms/se21/html/jvms-4.html |
What is a CLASS file?
A .class file is the compiled form of a Java program. When you compile a .java source file with javac, the compiler emits one .class file per class or interface, containing Java bytecode: a compact, platform-independent instruction set executed by the Java Virtual Machine (JVM). The format has been part of Java since version 1.0 in 1995–1996 and is defined precisely in Chapter 4 of the Java Virtual Machine Specification. “Compile once, run anywhere” is exactly this file: the same .class runs unchanged on any operating system that has a JVM. Its MIME type is application/java-vm.
A .class is not meant to be opened like a document. To run it you need Java installed and a main method (java MyClass); to read what it does you must decompile or disassemble it, because bytecode is not human-readable and the compiler discards comments and most local-variable names. You also rarely deal with just one: real applications, libraries and most Minecraft mods ship as a JAR, which is a ZIP of many .class files plus a manifest. Everything below is the internal structure the JVM reads, in the order the bytes appear.
The header: magic, minor and major version
Every class file opens with a fixed 8-byte header. The specification defines the whole file as a single big-endian structure, and the first fields identify it and stamp its version.
ClassFile {
u4 magic; // 0xCAFEBABE
u2 minor_version; // usually 0
u2 major_version; // 52 = Java 8, 61 = Java 17, 65 = Java 21
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count - 1];
u2 access_flags; // public / final / abstract / interface ...
u2 this_class; // index into constant_pool
u2 super_class; // index into constant_pool (0 only for Object)
u2 interfaces_count; u2 interfaces[];
u2 fields_count; field_info fields[];
u2 methods_count; method_info methods[];
u2 attributes_count; attribute_info attributes[];
}
The u1/u2/u4 notation means unsigned 1-, 2- and 4-byte big-endian integers. The magic is always 0xCAFEBABE, chosen by the format’s designers as a memorable hexadecimal word. The major_version is the field behind one of the most common Java errors: it records which JDK compiled the file, and if you try to run a class on an older JVM than the one that built it, the JVM throws UnsupportedClassVersionError. The numbering increments by one per release — 52 for Java 8, 61 for Java 17, 65 for Java 21 — and a minor_version of 65535 marks a class that uses that release’s preview features.
The constant pool: the file’s symbol table
Directly after the header comes the constant pool, and it is the structural heart of the class file. It is a table of entries that every other part of the file refers to by 1-based index rather than storing literals inline. A method that calls System.out.println("hi") does not embed those strings; it holds constant-pool indices that chain to the class name, the field, the method name and signature, and the string literal.
| Tag | Constant kind |
|---|---|
1 | Utf8 — a modified-UTF-8 string (names, signatures, literals) |
3 / 4 | Integer / Float — 4-byte numeric constants |
5 / 6 | Long / Double — 8-byte constants (take two pool slots) |
7 | Class — a class or interface, by name index |
8 | String — a string literal, by Utf8 index |
9/10/11 | Fieldref / Methodref / InterfaceMethodref |
12 | NameAndType — a name plus a type descriptor |
Two quirks trip up parsers. The pool is indexed from 1, not 0, and Long and Double entries each occupy two consecutive slots, so the next usable index jumps by two. All symbolic references — the names of classes, methods and fields the code touches — are Utf8 strings in this pool, which is precisely why bytecode retains enough information to be decompiled: the human-meaningful names survive here even though the source text does not.
Fields, methods and the Code attribute
After the class-level metadata (access_flags, this_class, super_class and the interface list) come the fields and methods tables. Each method_info records the method’s name and a descriptor — a compact type signature such as (Ljava/lang/String;)I, meaning “takes a String, returns an int” — plus a list of attributes. The important one is the Code attribute, which carries the actual executable bytecode.
Code_attribute {
u2 max_stack; // operand-stack depth this method needs
u2 max_locals; // local-variable slots
u4 code_length;
u1 code[code_length]; // the bytecode instructions
... exception_table, attributes (LineNumberTable, etc.)
}
The code array is a stream of one-byte opcodes, each optionally followed by operands. The JVM is a stack machine: instructions push and pop operands rather than using registers. So iload_1 pushes local variable 1, iadd pops two ints and pushes their sum, invokevirtual #7 calls a method named by constant-pool entry 7, and ireturn returns an int. The max_stack and max_locals fields let the verifier check the method before it ever runs. Optional attributes like LineNumberTable map bytecode offsets back to source line numbers, which is what makes a stack trace readable.
How the JVM loads and verifies a class
Running a .class is not a simple read. When the JVM first needs a class it goes through loading, linking and initialisation. Loading reads the bytes and builds an internal representation. Linking has three steps: verification checks that the bytecode is well-formed and type-safe (the stack never underflows, jumps land on real instructions, types match), preparation allocates static fields with default values, and resolution turns the symbolic constant-pool references into direct ones the first time each is used. Initialisation finally runs the static initialisers. The verification step is a real security boundary: it is why the JVM can load code from untrusted sources without letting malformed bytecode corrupt the runtime, and it is why a hand-edited or truncated .class is usually rejected with a VerifyError rather than crashing.
Reading a class: decompilers and javap
Because the constant pool preserves names and the method structure is intact, a .class can be reconstructed into approximate Java source. A decompiler such as JD-GUI (a GUI), or CFR, Fernflower and Procyon (command-line), reads the bytecode and rebuilds readable Java. What you get back is close to the original but not identical: comments are gone, original local-variable names are usually lost (replaced by generated ones unless a LocalVariableTable attribute was kept), and deliberately obfuscated code decompiles into near-gibberish. For a lower-level view, the JDK ships javap: javap -c -p MyClass disassembles the class into readable bytecode mnemonics and the constant pool without reconstructing source. Opening the raw .class in a text editor just shows binary noise; these tools are the way to inspect it.
Frequently asked questions
Why do I get UnsupportedClassVersionError?
The class was compiled by a newer Java than the JVM you are running. The class file’s major_version encodes the JDK that built it (52 = Java 8, 61 = Java 17, 65 = Java 21), and an older JVM refuses a higher number. Install a JDK at least as new as the one that compiled the class, or recompile the source targeting your version.
What is the difference between a .class and a .jar?
A .class is one compiled class. A JAR is a ZIP archive bundling many .class files plus a manifest that can name the entry-point class, used to ship a whole program or library. Loose .class files mostly appear inside a project’s build folder or inside an unzipped JAR; applications are distributed as JARs, not as bare classes.
References
- Oracle — The Java Virtual Machine Specification, Ch.4: The class File Format
- Oracle — javap tool (class disassembler)
- Eclipse Adoptium (Temurin OpenJDK) — downloads
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.