Can you create an array of generic type
This breaks type safety — the error is not caught at compile time.
🟢 Junior Level
No, you cannot directly. Java does not allow creating arrays of generic types due to type erasure.
// ❌ Cannot do this
public class Box<T> {
private T[] array = new T[10]; // compilation error: "generic array creation"
}
Why: Arrays in Java know their type at runtime, while generics lose their type after compilation (type erasure). These two mechanisms are incompatible.
Solutions:
// Solution 1: Array of Object with cast
public class Box<T> {
private T[] array = (T[]) new Object[10]; // unchecked warning
}
// Solution 2: ArrayList instead of array
public class Box<T> {
private List<T> list = new ArrayList<>();
}
// Solution 3: Pass Class<T>
public class Box<T> {
private T[] array;
public Box(Class<T> type, int size) {
array = (T[]) Array.newInstance(type, size);
}
}
🟡 Middle Level
Why is it not allowed?
Conflicting models:
- Arrays — reified (know their type at runtime)
- Generics — type erasure (type is lost)
// If it were allowed:
List<String>[] stringLists = new List<String>[10];
Object[] objects = stringLists; // arrays are covariant
objects[0] = List.of(42); // List<Integer> — compiler doesn't complain!
String s = stringLists[0].get(0); // ClassCastException!
This breaks type safety — the error is not caught at compile time.
Working solutions
1. Unchecked cast:
public class GenericStack<T> {
private T[] elements;
private int size = 0;
@SuppressWarnings("unchecked")
public GenericStack(int capacity) {
elements = (T[]) new Object[capacity]; // unchecked warning
}
public void push(T item) {
elements[size++] = item;
}
public T pop() {
return elements[--size];
}
}
2. Reflection:
public class GenericArray<T> {
private final T[] array;
public GenericArray(Class<T> type, int size) {
array = (T[]) Array.newInstance(type, size);
}
public void set(int index, T value) {
array[index] = value;
}
public T get(int index) {
return array[index];
}
}
// Usage
GenericArray<String> strings = new GenericArray<>(String.class, 10);
strings.set(0, "Hello");
3. Collections instead of arrays:
// Best solution in most cases
public class Box<T> {
private final List<T> items = new ArrayList<>();
public void add(T item) { items.add(item); }
public T get(int index) { return items.get(index); }
}
Common mistakes
- Ignoring unchecked warning: ```java // ⚠️ Warning suppressed, but the problem remains T[] array = (T[]) new Object[10];
// Better — document why this is safe
2. **Heap pollution:**
```java
// Dangerous — can put wrong type
Object[] raw = new Object[10];
String[] strings = (String[]) raw; // ClassCastException!
🔴 Senior Level
Internal Implementation
Why arrays are reified:
JVM specification:
- Arrays store component type in class file
- Runtime check on every access
- ArrayStoreException on wrong type
// Example
String[] arr = new String[10];
arr[0] = "Hello"; // OK
arr[1] = 42; // ArrayStoreException at runtime!
Type erasure conflict:
// If generic arrays were allowed:
List<String>[] lists = new List<String>[5];
Object[] obj = lists; // covariant
obj[0] = new ArrayList<Integer>(); // OK for compiler
String s = lists[0].get(0); // ClassCastException!
// Array cannot check element type at runtime,
// because List<String> and List<Integer> are the same raw type after erasure
Architectural Trade-offs
Approaches to generic arrays:
| Approach | Pros | Cons |
|---|---|---|
| Object[] + cast | Simple | Unchecked warning |
| Reflection | Type-safe | Needs Class |
| Collections | Safe | More overhead |
Edge Cases
1. Generic varargs:
// Varargs are arrays!
public static <T> List<T> asList(T... items) {
return Arrays.asList(items);
}
// ⚠️ Heap pollution warning
asList("a", "b", "c"); // OK
// But compiler warns
// @SafeVarargs fixes it
@SafeVarargs
public static <T> List<T> safeAsList(T... items) {
return Arrays.asList(items);
}
2. Nested generic arrays:
// Even harder — nested types
public class Matrix<T> {
// ❌ Cannot do this
private T[][] matrix = new T[10][10]; // error
// ✅ Via Reflection
private T[][] matrix;
public Matrix(Class<T> type, int rows, int cols) {
matrix = (T[][]) Array.newInstance(type, rows, cols);
}
}
3. ArrayList.toArray() problem:
List<String> list = List.of("a", "b", "c");
// ❌ Cannot do this
String[] array = (String[]) list.toArray(); // ClassCastException
// toArray() returns Object[]
// ✅ Correct approach
String[] array = list.toArray(new String[0]);
// Or Java 11+
String[] array = list.toArray(String[]::new);
Performance
Array vs ArrayList:
Operation | Array | ArrayList
------------------|--------------|----------
Access | 1 ns | 1 ns
Add | N/A (fixed) | 1-10 ns (resize)
Memory | Minimum | + overhead
Type check | Runtime | Compile time
Generic array creation:
- Object[] + cast: Zero overhead
- Reflection: ~5-10 ns per creation
- Collections: +10-20% memory
Production Experience
Java collections internal:
// ArrayList internal — uses Object[] + cast
public class ArrayList<E> {
private transient Object[] elementData; // NOT E[]
@SuppressWarnings("unchecked")
public E get(int index) {
return (E) elementData[index]; // unchecked cast
}
}
// HashMap — similarly
transient Node<K,V>[] table; // array of raw Node
// This is safe because ArrayList controls all writes internally
// and does not allow elements of wrong type.
Safe generic array:
public class SafeGenericArray<T> {
private final Object[] array;
private final Class<T> type;
public SafeGenericArray(Class<T> type, int size) {
this.type = type;
this.array = new Object[size];
}
public void set(int index, T value) {
if (!type.isInstance(value)) {
throw new IllegalArgumentException();
}
array[index] = value;
}
@SuppressWarnings("unchecked")
public T get(int index) {
return (T) array[index];
}
}
Best Practices
// ✅ Use collections instead of arrays
List<T> list = new ArrayList<>();
// ✅ If you need an array — Object[] + cast
@SuppressWarnings("unchecked")
private T[] array = (T[]) new Object[size];
// ✅ @SafeVarargs for varargs methods
@SafeVarargs
public static <T> T[] merge(T[] a1, T[] a2) { }
// ✅ Reflection when you need a type-safe array
T[] array = (T[]) Array.newInstance(type, size);
// ❌ new T[]
// ❌ Ignoring unchecked warnings without justification
// ❌ Heap pollution — exposing generic array externally
🎯 Interview Cheat Sheet
Must know:
new T[]— compilation error: “generic array creation”- Reason: arrays are reified (know type at runtime), generics — type erasure (type is lost)
- Solution 1:
Object[]+ unchecked cast(T[]) new Object[size] - Solution 2: Reflection —
Array.newInstance(type, size)withClass<T>passed - Solution 3: Use
ArrayList<T>instead of array - @SafeVarargs suppresses warnings for varargs methods
- ArrayList internally uses
Object[]+ unchecked cast
Frequent follow-up questions:
- Why can’t you create a generic array? — Conflict between reified arrays and type-erased generics
- How does ArrayList store elements? — Object[] elementData + unchecked cast on get()
- What is heap pollution? — When a generic collection contains elements of the wrong type
- Is unchecked cast in ArrayList safe? — Yes, ArrayList controls all writes internally
Red flags (DO NOT say):
- ❌ “Generic array can be created via unchecked cast without issues” — Heap pollution is possible
- ❌ “Generic arrays work in Java” — Banned at compiler level
- ❌ “ArrayList uses T[] internally” — ArrayList uses Object[], not T[]
- ❌ “Heap pollution is a JVM error” — It’s a compile-time warning, a type safety issue
Related topics:
- [[11. What are Generics in Java]]
- [[13. What is type erasure]]
- [[18. Can you use primitive types as generic parameters]]
- [[19. What are raw types and why should you avoid them]]