Java class file format
Compiled Java bytecode, executed by the JVM.
- MIME type
- application/java-vm
- Extensions
- .class
- Category
- Executables & bytecode
Magic-number signature
| 0x00000000 | CAFEBABE | ···· | 'CAFEBABE' magic |
About the Java class file format
A .class file is one compiled Java type — a class, interface, enum or record — in the JVM's own container format, and almost all of it is one structure: the constant pool. Class names, method names, field descriptors, string literals and every symbolic reference live there as numbered entries, and the rest of the file refers to them by index rather than by text. That is why a class file is so compressible inside a JAR, why renaming a class changes bytes all over the file, and why every offset after the constant pool is variable: the pool's length depends entirely on how many names the type mentions.
Header layout, byte by byte
| Offset | Length | Field | Meaning |
|---|---|---|---|
| 0 | 4 | magic | CA FE BA BE, chosen by James Gosling before Java had a name and shared, awkwardly, with Apple's universal binaries. It is the only fixed-value field in the file. |
| 4 | 2 | minor_version | Almost always 0. The value 65535 has a specific meaning: the class uses preview features and will only load on exactly the JDK that compiled it, which is the real explanation behind a preview-feature class failing on a matching major version. |
| 6 | 2 | major_version | The class file version, and the field behind every UnsupportedClassVersionError. Since Java 5 it is the feature release plus 44 — Java 8 is 52, Java 17 is 61, Java 21 is 65 — and these two bytes are what a runtime compares against its own maximum before reading anything else. |
| 8 | 2 | constant_pool_count | One more than the number of pool entries, because the pool is indexed from 1 and index 0 is reserved. A small utility class runs to a few dozen; a large framework class can approach the 65535 ceiling, which is a real limit generated code sometimes hits. |
| 10 | variable | constant_pool | Entries back to back, each opening with a one-byte tag that fixes its length: tag 1 is a UTF-8 string with a two-byte length prefix, tag 7 a class reference, tag 10 a method reference, tag 8 a string. Tags 5 and 6 (long and double) each consume two index slots — a rule that has broken more hand-written parsers than any other part of the format. |
| variable | 2 | access_flags | First field after the pool. 0x0001 public, 0x0010 final, 0x0200 interface, 0x4000 enum, and 0x0020 (ACC_SUPER) set on essentially everything compiled since 1997 for legacy invokespecial semantics — a plain public class typically reads 0x0021. |
| variable | 2 | this_class | Index of the pool entry naming this type, in internal form with slashes rather than dots. It has to agree with the file's path inside the JAR, which is why renaming a .class file on disk produces a NoClassDefFoundError that names both spellings. |
| variable | 2 | super_class | Index of the superclass entry, normally java/lang/Object. It is 0 only for java/lang/Object itself, the single class in the world with no parent. |
| variable | 2 | interfaces_count | How many direct superinterfaces follow, each as a two-byte pool index. Then come fields, methods and class attributes, every one of them length-prefixed, so the file must be read sequentially from the pool onward — there is no table of contents. |
Telling it apart from its neighbours
| Easily confused with | How to tell |
|---|---|
| Mach-O (universal/fat) | Both open CA FE BA BE. Read bytes 4-7: a class file has minor_version then major_version, and major_version is at least 45 (Java 1.1) and currently in the sixties or seventies, while a universal binary has nfat_arch there — a small architecture count whose high half is zero. A nonzero value in bytes 6-7 above 44 means class file. |
| Java JAR | A JAR does not contain a class file at offset 0; it is a ZIP that begins 50 4B 03 04 and holds compressed class files inside. Seeing CA FE BA BE inside a JAR's bytes is expected — it just is not at the front, and the entry names in the central directory are what identify the archive. |
| Android DEX | Android tooling compiles .class files and then throws them away: d8 merges them into a DEX file, which begins 'dex' and a newline and uses a register-based instruction set rather than the JVM's stack machine. An APK therefore contains no .class entries at all, which is the quickest way to tell an APK apart from a JAR that happens to target Android. |
| Java source (.java) | Stated because build directories mix them: a .java file is plain text and a .class file starts with a byte that is not valid UTF-8 text. Any tool that opens a .class and shows readable class and method names is reading UTF-8 constant-pool entries, not source. |
How these files break
- A major_version newer than the runtime. Not corruption at all, but it is what people are usually looking at: the JVM reads bytes 6-7, sees a version above its maximum, and throws UnsupportedClassVersionError before parsing anything else. Compiling with release 21 and running on Java 17 produces exactly this.
- Truncation. Because everything after the constant pool is length-prefixed and sequential, a class file cut short fails with ClassFormatError at whatever structure it was in the middle of, and the message rarely points at the real cause. The file being short is easier to see than the message.
- A byte edited inside the constant pool. Changing a string literal to a different length without fixing its two-byte length prefix desynchronises every subsequent entry, so the parser reads a tag from the middle of a name and reports an unknown constant tag. This is why patching class files needs a library rather than a hex editor.
- Text-mode transfer. The old FTP problem still reaches class files inside legacy build pipelines: CR LF translation shifts everything after the first occurrence, and because the constant pool is a stream of length-prefixed entries, the failure is a nonsense tag rather than a clean magic mismatch.
Where the format stands today
The class file is the JVM's actual interface: Java, Kotlin, Scala, Groovy and Clojure all compile to it, which is what makes them one ecosystem rather than five, and the format's stability is why a library compiled in 2005 still links against code compiled today. It is rarely handled on its own — classes travel inside JARs, WARs, module images and container layers — but it is what every bytecode tool, obfuscator, coverage agent and framework that generates proxies at runtime actually manipulates. Android is the notable exception: it consumes class files at build time and ships DEX instead. For a person with a hex editor, the useful property is that a class file is largely self-describing text: the constant pool spells out every class, method and field the type touches, so its dependencies are readable without decompiling anything.
Open Java class files on this site
Every one of these runs in your browser — the file never leaves your machine.
Related formats
Formats that are easy to confuse with Java class file — compare their leading bytes.
| Format | First bytes | Extension |
|---|---|---|
| Java JAR | 50 4B 03 04 | .jar |
| Mach-O (universal/fat) | CA FE BA BE | .dylib |
| Android DEX | 64 65 78 0A | .dex |