skip to content

Cannot Instantiate or Array Type Parameters

You cannot write new T() or new T[] because at runtime there is no T; the workarounds are a Class<T> token with Array.newInstance, or a supplied factory. Interviewers ask you to implement a generic factory to see whether you reach for the token.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

Why can't you write `new T()` inside a generic class or method in Java, and what is the standard workaround?

level: middleimportance: must knowfreq 70%

answer

  1. Erasure: T becomes Object/bound at runtime
  2. No runtime class -> no constructor to call
  3. Class<T> token + getDeclaredConstructor().newInstance()
  4. Supplier<T> / factory (preferred, type-safe, no reflection)
  5. Class.newInstance() deprecated since Java 9

basics

~20 s

Java erases the generic type T at compile time, so at runtime the program doesn't know which class T is and can't call its constructor. The usual fix is to pass a Class<T> object and call clazz.getDeclaredConstructor().newInstance(), or pass a factory/supplier that creates the object for you.

solid answer

~40 s

Generics in Java are implemented with type erasure: the type parameter T exists only at compile time and is replaced by its bound (usually Object) in the bytecode. So `new T()` is impossible because at runtime there is no information about which concrete class T stands for, and the JVM wouldn't know which constructor to invoke. The two standard workarounds are: (1) pass a `Class<T>` type token and create instances reflectively via `clazz.getDeclaredConstructor().newInstance()`; or (2) pass a factory abstraction such as `Supplier<T>` or a custom factory interface, letting the caller decide how to build the object. The factory/Supplier approach is generally preferred today because it is type-safe, avoids reflection, handles constructors with arguments, and surfaces failures at compile time rather than as runtime reflective exceptions.

code

java · 17 lines
java
// Won't compile:
class Box<T> {
    // T value = new T();  // error: type parameter T cannot be instantiated directly
}

// Workaround A: Class<T> type token + reflection
static <T> T makeViaToken(Class<T> type) throws ReflectiveOperationException {
    return type.getDeclaredConstructor().newInstance();
}

// Workaround B: Supplier<T> factory (preferred)
static <T> T makeViaFactory(java.util.function.Supplier<T> factory) {
    return factory.get();
}

String a = makeViaFactory(String::new);          // ""
ArrayList<Integer> b = makeViaFactory(ArrayList::new);

go deeper

for a junior

Knows new T() doesn't compile and that you can pass a factory/Supplier or a Class object instead, even if the erasure mechanics are fuzzy.

for a middle

Explains type erasure clearly, knows both the Class<T> token and Supplier<T> workarounds, and can write the reflective newInstance call.

for a senior

Articulates why Supplier is preferred (compile-time safety, no reflection, arg constructors), knows erasure goes to the bound not always Object, and notes Class.newInstance() deprecation.

for a principal

Frames it against reified generics in other languages, the backward-compatibility rationale for erasure, and API-design implications of choosing token-vs-factory in a framework.

## The problem A **generic class** or **generic method** is parameterized by a *type parameter* — a placeholder like `T` that stands for some real type the caller chooses, e.g. `class Box<T>` or `<T> T make()`. You might naturally want to create a fresh `T` inside such code: ```java class Box<T> { T value = new T(); // DOES NOT COMPILE } ``` The compiler rejects this. To understand why, you need **type erasure**. ## What type erasure is Java added generics in Java 5 but had to stay backward-compatible with pre-generics code and with the existing JVM. The chosen implementation is *erasure*: generics are a **compile-time-only** feature. The compiler checks your types, then **erases** the type parameters from the bytecode. Every `T` is replaced by its *bound* — `Object` if `T` is unbounded, or the leftmost bound if you wrote `<T extends Number>` (then `T` becomes `Number`). The compiler inserts hidden casts where needed so the code still behaves correctly. The consequence: **at runtime, a `Box<String>` and a `Box<Integer>` are the exact same class `Box`** — there is no stored memory of what `T` was. The type argument is simply *not present* at runtime. This is called the type parameter being *non-reifiable* (a *reifiable* type is one whose full type information survives to runtime; generic type arguments are not reifiable). ## Why `new T()` fails To execute `new SomeClass()`, the JVM must (a) know the exact class to allocate and (b) know which constructor to call. With `new T()`, after erasure there is no class named `T` and no way to recover the concrete type the caller picked. The compiler also can't even prove that `T` *has* a no-argument constructor. So `new T()` is forbidden outright — it is a compile error, not a runtime surprise. ## Workaround 1: pass a `Class<T>` type token The caller hands you a *type token* — a `Class<T>` object that *does* carry the concrete class at runtime — and you instantiate reflectively: ```java static <T> T make(Class<T> type) throws ReflectiveOperationException { return type.getDeclaredConstructor().newInstance(); } // call: String s = make(String.class); ``` Downsides: it only works if `T` has an accessible matching constructor; it throws *reflective* exceptions at runtime instead of giving compile-time safety; and constructors that need arguments are awkward. (Note: `Class.newInstance()` is deprecated since Java 9 — use `getDeclaredConstructor().newInstance()`.) ## Workaround 2: pass a factory / `Supplier<T>` (preferred) Let the caller supply the construction logic: ```java static <T> T make(Supplier<T> factory) { return factory.get(); } // call: StringBuilder sb = make(StringBuilder::new); Point p = make(() -> new Point(1, 2)); // constructor with args, no problem ``` This is **type-safe at compile time**, needs no reflection, naturally supports constructor arguments, and fails fast if the type can't be built. For these reasons it is the modern idiom; the `Class<T>` token is mostly used when you also need the class for other reflective reasons (e.g. frameworks). ## Key takeaway You cannot directly instantiate a type parameter because erasure removes the type at runtime. Move the *act of creation* to something that does know the type: a `Class<T>` token (reflection) or, better, a `Supplier<T>`/factory provided by the caller.

  • Why is Supplier<T> usually preferred over passing a Class<T>?
    It's checked at compile time, needs no reflection, supports constructors with arguments, and surfaces errors as compile errors rather than runtime ReflectiveOperationExceptions.
  • What does T erase to if you declare <T extends Number>?
    It erases to Number (the leftmost/only bound), not Object; the compiler inserts casts back to the used type as needed.

saying these in an interview costs you the question

  • Claiming Java generics are reified like C# generics
  • Saying new T() compiles but throws at runtime (it's a compile error)
  • Recommending Class.newInstance() without noting it's deprecated
  • Forgetting that T might not have a no-arg constructor

context

open as a page

Why does Java reject `new T[]` and `new List<String>[]`, and how do you create such arrays safely?

level: seniorimportance: must knowfreq 62%

basics

~20 s

Arrays in Java remember their element type at runtime and check every store against it, but generic types are erased and lost at runtime. Allowing generic arrays would let bad values slip in undetected, so the compiler forbids new T[] and new List<String>[]. The common fix is to create an Object[] (or use Array.newInstance with a Class token) and cast.

open as a page

When creating instances of a type parameter, when should you use a `Supplier<T>`/factory versus a `Class<T>` token?

level: juniorimportance: should knowfreq 35%

basics

~20 s

Use a Supplier<T> (or factory) when you just need to make new objects — it's simple, checked by the compiler, works with any constructor, and uses no reflection. Use a Class<T> token when you also need the actual class for other reasons, like reflection, casting, or building a real typed array.

open as a page

What is a `Class<T>` type token, and how does it let generic code work around erasure?

level: middleimportance: should knowfreq 48%

basics

~20 s

A type token is just a Class<T> object (like String.class) that you pass into generic code. Because the Class object still knows the concrete type at runtime, the code can use it to create instances, cast, or build arrays even though the type parameter T itself was erased.

open as a page

Why did Java implement generics with type erasure rather than reified generics, and what restrictions does that choice impose?

level: principalimportance: should knowfreq 40%

basics

~20 s

Java chose erasure so that generic code stays fully compatible with older non-generic code and runs on the existing JVM without changing the bytecode format. The price is that type arguments vanish at runtime, which is why you can't do new T(), new T[], obj instanceof T, or overload methods that differ only by their type argument.

open as a page