skip to content

Java arrays support primitives (int[]) but generics do not (no List<int>). Why the asymmetry?

level: seniorimportance: should knowfreq 35%

answer

  1. Arrays reified, generics erased
  2. JVM has iastore/aaload per primitive array
  3. Erasure chosen for backward compatibility
  4. Erased storage is Object -> no primitives
  5. Project Valhalla = future fix

basics

~20 s

Arrays are a built-in language feature that knew about primitives from day one and the JVM has separate bytecode for primitive arrays. Generics were added later and use type erasure, where elements are treated as Object, which can't hold a primitive. So arrays got primitives, generics didn't.

solid answer

~50 s

The difference is historical and how each is implemented. Arrays are reified: they existed from Java 1.0, are first-class in the JVM, and the bytecode has distinct instructions for each primitive array type (iastore for int[], aastore for Object[]). The JVM literally knows an int[] is a contiguous block of ints. Generics arrived in Java 5 and were retrofitted via type erasure to preserve backward compatibility: the type argument is checked at compile time then erased, and the container stores elements as Object. A primitive can't be stored in an Object slot, so primitive type arguments are forbidden. In short, arrays were designed with primitives natively; generics were bolted on with erasure that only works for references. Project Valhalla aims to remove this asymmetry by introducing value types and specialized generics so List<int> could eventually work.

go deeper

for a junior

Knows int[] is allowed but List<int> is not, even if not the deep reason.

for a middle

Can say arrays are built-in/older and generics use erasure that stores Object, so primitives don't fit.

for a senior

Articulates reified arrays (per-primitive JVM bytecode) vs erased generics (backward-compatibility choice), and ties in the related generic-array restriction.

for a principal

Discusses the language-design trade-offs of erasure vs reification, migration compatibility, and the Valhalla roadmap toward specialized generics.

## Setting up the terms **Reified vs erased.** A type is **reified** if its full type information is available *at runtime*. It is **erased** if the compiler uses it for checking then throws it away, leaving no runtime trace. - **Arrays are reified.** An `int[]` and a `String[]` are genuinely different types at runtime; the JVM tracks the component type and will throw `ArrayStoreException` if you try to store the wrong thing in an `Object[]` that's really a `String[]`. - **Generics are erased.** `List<Integer>` and `List<String>` are both just `List` at runtime. The `<Integer>`/`<String>` exists only at compile time. ## Why arrays can hold primitives Arrays were in Java from version 1.0 and are a **first-class, built-in** construct — not a library class. The JVM has *dedicated bytecode* per element kind: - `iastore`/`iaload` for `int[]`, `dastore`/`daload` for `double[]`, `bastore` for `byte[]/boolean[]`, etc. - `aastore`/`aaload` for reference arrays (`Object[]`, `String[]`). Because the JVM has a separate, type-specialized representation for each primitive array, an `int[]` is a contiguous block of raw 4-byte ints with no boxing. The language and VM were *designed* to know about primitives here. ## Why generics cannot Generics were added in **Java 5 (2004)**, long after the language and a huge ecosystem of libraries already existed. The designers chose **type erasure** specifically for **backward compatibility / migration compatibility**: pre-generics code (`List`) and generic code (`List<String>`) had to interoperate and compile to the same `List` runtime type, so old `.class` files and new ones could mix. To achieve that, the compiler erases the type argument and the collection internally stores elements as `Object`. A primitive `int` is **not** a subtype of `Object` — only reference types are. So there is no way to put a raw `int` into the `Object`-typed storage that erasure produces. Rather than generate the impossible, the language **forbids primitive type arguments**, and you box into the wrapper (`Integer`) instead. This is the crux of the asymmetry: - Arrays: VM-level, per-primitive specialization → primitives are natural. - Generics: a compile-time, erasure-based overlay that only speaks `Object` → primitives can't fit. ## A related consequence: generic arrays are also restricted The same erasure mismatch means you can't create a generic array like `new T[10]` or `new List<String>[10]` — arrays are reified (need the runtime type) but generics are erased (don't have it). This is a sibling restriction worth knowing, even though the specific topic here is primitives. ## The future: Project Valhalla The JDK's **Project Valhalla** is introducing **value types / primitive classes** and **specialized generics**, with the goal that generics can eventually be parameterized over primitives/value types (so something like `List<int>` could be specialized to flat, boxing-free storage). Until that ships broadly, the rule stands: arrays yes, generics no. ## How to answer *Arrays are reified and were built into the VM with per-primitive bytecode from the start, so `int[]` is native. Generics were added later with type erasure for backward compatibility, storing elements as `Object`, which can't hold a primitive — hence no `List<int>`, and you box to `Integer`. Project Valhalla is the planned fix.*

  • Why can't you write new List<String>[10] either?
    Generic array creation is forbidden for the same erasure reason: arrays are reified and need the runtime component type, but generics are erased, so the type isn't available. The compiler rejects it (you can do a raw or @SuppressWarnings workaround).
  • What is Project Valhalla and how does it relate?
    It's a JDK effort adding value types and specialized generics so generics can be parameterized over primitives/value types with flat, boxing-free layout — eventually removing the arrays-vs-generics asymmetry for primitives.

Arrays are like factory machines built to stamp a specific metal (each primitive). Generics are a paper template laid over an existing object-only conveyor belt — the belt only carries boxed parcels, so loose coins (primitives) have to be put in a box first.

saying these in an interview costs you the question

  • Saying generics support primitives 'under the hood' via the JIT
  • Claiming arrays are also erased (they are reified)
  • Believing erasure was an oversight rather than a deliberate backward-compatibility choice

context