Some JVM runtime types never come from a classfile at all — array types such as `String[]` are one example. How does the JVM create such types, and how do runtime-generated types like lambda implementation classes come into existence?
answer
- Array classes created by the JVM, no bytes exist
- Array's loader = component type's loader; primitives → bootstrap
- Lambdas: invokedynamic + LambdaMetafactory spins a class on first run
- Hidden classes: unnameable, unreferenceable, separately unloadable
- Proxies/mocks/ORM enhancers = generated byte[] + define
basics
~20 sArray classes and primitive types have no binary representation: the JVM synthesises them directly, and an array class's defining loader is its component type's loader (bootstrap for primitive arrays). Lambda implementation classes do come from bytes, but bytes generated in memory at first execution and defined as hidden classes.
solid answer
~50 sTwo different mechanisms are at work. **Types the JVM creates itself.** Array classes are *created*, not loaded from bytes — there is no `[Ljava/lang/String;.class` anywhere. The JVM builds the runtime type on demand, and its defining loader is the defining loader of the component type (arrays of primitives are associated with the bootstrap loader). Creating `String[][]` implies creating `String[]` first. Primitive types and `void` likewise have mirrors (`int.class`) that the JVM materialises rather than loads. **Types generated at runtime.** Lambdas compile to an `invokedynamic` call site; the first time it executes, `LambdaMetafactory` generates a small implementation class *in memory* and defines it via `MethodHandles.Lookup.defineHiddenClass` (Java 15+; formerly the internal `Unsafe.defineAnonymousClass`). Hidden classes are not entered into any loader's name map, cannot be referenced from another class's constant pool, and can be unloaded independently — which suits short-lived generated helpers. `java.lang.reflect.Proxy`, mocking libraries and ORM enhancers use the ordinary or lookup-based define paths for the same purpose.
code
text · 4 lines[class,load] com.acme.Svc$$Lambda/0x000078a1c8021c00 source: __JVM_DefineClass__
[class,load] jdk.proxy2.$Proxy31 source: __JVM_DefineClass__
at com.acme.Svc$$Lambda/0x000078a1c8021c00.apply(Unknown Source)go deeper
Know that arrays and primitives have Class objects the JVM creates itself, and that lambdas do not produce extra class files.
Explain the array-loader rule and the invokedynamic + LambdaMetafactory mechanism at first execution.
Add hidden classes and their properties, recognise generated types in class-load logs and stack traces, and connect rising class counts to code-generation hot spots.
Discuss why the platform introduced a narrower type kind at all — decoupling generated helpers from loader namespaces and lifetimes is what keeps heavy runtime code generation viable in long-lived processes.
## Two categories of "no classfile" It is tempting to assume every runtime type in a JVM began life as a `.class` file. Two large categories break that assumption, and they break it in different ways: 1. Types the JVM **creates** with no binary representation at all — array classes, primitive types, `void`. 2. Types that **do** have classfile bytes, but bytes that were generated in memory during the run and never existed as a file. ## Array classes: created, not loaded There is no artifact anywhere describing `String[]`. When the JVM needs the array type, it manufactures the runtime type itself: the members are fixed and known (a `length` field, `clone()`, and the members inherited from `Object`), the supertype relationships are defined by the specification (arrays are `Object` and implement `Cloneable` and `Serializable`), and covariance follows the component type. The rule people actually get asked about is the **defining loader**: an array class's defining loader is the defining loader of its component type. So `com.acme.Order[]` belongs to whichever loader defined `com.acme.Order`, while `int[]` — having a primitive component — is associated with the bootstrap loader. Multi-dimensional types are built up recursively: creating `Order[][]` requires `Order[]`, which requires `Order`. Primitive types and `void` follow the same spirit: `int.class` and `void.class` are mirrors the JVM materialises during startup; there is nothing to read. A practical consequence: an array class cannot be "missing" independently of its component type. Any failure you see relates to the component type — reflectively requesting `Class.forName("[Lcom.acme.Order;")` fails only because `com.acme.Order` cannot be found. ## Runtime-generated classes: real bytes, no file The second category goes through the normal load path, just with bytes produced by a program rather than a compiler writing to disk. **Lambdas.** A lambda expression does *not* compile into an anonymous inner class file. The compiler emits an `invokedynamic` instruction whose bootstrap method is `LambdaMetafactory`. On the first execution of that call site, the metafactory spins a small class implementing the target functional interface, wired to the lambda body (which the compiler emitted as a private synthetic method on the enclosing class), and returns a `CallSite` that the JVM links permanently. Subsequent executions of the call site do no work. This design is why lambdas add no `Foo$$1.class` files to your JAR and why the strategy could be changed without recompiling code. **Hidden classes.** Since Java 15, generated helpers like these are defined through `MethodHandles.Lookup.defineHiddenClass(byte[], boolean, Option...)`. A hidden class: - is not discoverable by name (`Class.forName` cannot find it) and is not entered into a loader's class-name map; - cannot be named in another class's constant pool, so nothing can hold a static reference to it; - reports a synthetic name with an implementation-specific suffix in stack traces; - can be unloaded independently of its defining loader (a normal class cannot); - may be declared a *nestmate* of the lookup class, giving it private access. This replaced the internal `sun.misc.Unsafe.defineAnonymousClass`, which many frameworks had reached for and which was removed in Java 17. **Proxies and enhancers.** `java.lang.reflect.Proxy` generates a class implementing a requested set of interfaces and defines it into a loader you supply. Mocking frameworks generate subclasses; ORMs generate enhanced entity subclasses for lazy loading and dirty tracking; serialization libraries generate accessors. All of these use a bytecode library to build a `byte[]` and then a define call. Once defined, these classes are utterly ordinary: verified, resolved, initialized and JIT-compiled by the same rules as compiled-from-source classes. ## How to recognise them at runtime - `-verbose:class` / `-Xlog:class+load` shows a source of `__JVM_DefineClass__` (or similar implementation-specific text) for classes defined from a byte array rather than a located resource. - Stack frames containing names with `$$Lambda` and an implementation suffix, or proxy names like `jdk.proxy2.$Proxy31`, indicate generated types. - A steadily rising loaded-class count in `jstat` or JFR, with names that look generated, points at a code-generation hot spot. ## Why an interviewer cares This question separates candidates who model "class loading" as "reading files" from those who model it as "deriving types". The array case shows the JVM manufacturing types with no bytes; the lambda case shows bytes manufactured with no file; the hidden-class case shows the platform adding a *narrower* kind of type when the full "nameable, permanent, loader-scoped class" contract is more than a generated helper needs.
- Which class loader defines `com.acme.Order[]`, and why does the answer matter?The same loader that defined `com.acme.Order` — an array class's defining loader is its component type's loader, and primitive arrays are associated with the bootstrap loader. It matters because array types inherit the namespace and lifetime of their component type: they are reclaimed with that loader and cannot exist in isolation from it.
- What does a hidden class give a framework that an ordinary defined class does not?It is not entered into a loader's name map, so it cannot be looked up by name or referenced from another class's constant pool, and it can be unloaded independently of its defining loader. For short-lived generated helpers such as lambda implementations that avoids permanently growing a loader's namespace and metadata footprint, and it can be given nestmate access to the lookup class's private members.
saying these in an interview costs you the question
- Believing there is a `.class` file somewhere for array types
- Claiming lambdas compile to anonymous inner classes on disk
- Thinking generated classes are interpreted or otherwise second-class to the JIT
- Saying every generated class can be found with `Class.forName` by its printed name
- Assuming an array class's loader is always the bootstrap loader