A class file is a big-endian binary structure consumed by the JVM. It begins
with 0xCAFEBABE, followed by u2 minor and major versions. A JVM accepts
only the versions defined for its implementation; class-file parsers must
reject unsupported versions rather than assume that a newer file is
backward-compatible.
Top-Level Structure #
After the magic and version, the file contains:
constant_pool_countand the indexed constant-pool entries;- class
access_flags,this_class, andsuper_class; - interface indexes;
field_infostructures;method_infostructures; and- class-level
attribute_infostructures.
Counts are unsigned u2 values, except an attribute’s attribute_length,
which is u4. Access flags describe the context: ACC_PUBLIC, ACC_FINAL,
ACC_SUPER, ACC_INTERFACE, ACC_ABSTRACT, ACC_SYNTHETIC,
ACC_ANNOTATION, ACC_ENUM, and ACC_MODULE are not all meaningful or legal
for every class-file kind.
Constant Pool and Names #
The constant pool is indexed from one; index zero is invalid except where a
specific structure reserves it. CONSTANT_Long and CONSTANT_Double consume
two consecutive indexes, with the second unusable. Entries include primitive
and string constants; Class; String; field, method, and interface-method
references; name-and-type pairs; method handles and method types; dynamic and
invoke-dynamic call sites; modules; and packages. References are symbolic:
for example, a CONSTANT_Methodref points through a class and name-and-type
entry instead of an in-memory method.
Class-file names use slash-separated internal names such as
java/lang/String; a binary name in source-oriented APIs uses dots. Field and
method descriptors encode types, for example Ljava/lang/String;, [I, and
(I[Ljava/lang/String;)V. CONSTANT_Utf8 uses the class-file modified UTF-8
encoding, which encodes the null character as C0 80 and represents UTF-16
surrogate code units individually. It is not interchangeable with a generic
UTF-8 decoder.
Members and Attributes #
Each field_info and method_info has access flags, name and descriptor
indexes, and an attribute table. A method’s Code attribute stores
max_stack, max_locals, bytecode, exception handlers, and nested attributes
such as line numbers or stack-map frames. Fields may carry ConstantValue;
classes and members carry metadata through attributes, including annotations,
signatures, nest information, records, modules, and debugging data. Unknown
attributes may be skipped only by using their declared length; their semantics
cannot be guessed from their name.
Safe Parsing #
Treat a class file as hostile input even when it originates from a build. Before every read, validate the remaining byte count; validate every count, index, tag, flag combination, descriptor, and attribute length; use checked arithmetic for offset plus length; and reject trailing structural inconsistencies. Enforce the format’s version and context rules before resolving symbolic references. The verifier adds execution-safety checks, but it is not a substitute for a bounded binary parser.
Tools such as javap -v display a decoded view, but transformations should use
a maintained library that supports the target class-file version and preserves
unknown attributes where required.
Comments
Read or comment on GitHub (sign-in required to comment)