«Generic array creation» — an error that infuriates every Java developer
\n\nHave you ever written something like new T[10] and got a red squiggly line from the compiler? If so, you are not alone. The question «How can I create a generic array in Java?» on Stack Overflow has gathered hundreds of thousands of views. And this is no coincidence: creating a generic array in Java is one of those topics where theory diverges from practice, and the IDE refuses to understand what you want from it.
In this article, we will break down why Java forbids generic arrays, how to work around the limitation without losing type safety, and when an array is still better than ArrayList. Let's go!
Why doesn't new T[10] work? The root cause — type erasure
\n\nTo understand how to create a generic array in Java, you first need to realize why the compiler complains. It's due to type erasure. Java generics exist only at compile time. At runtime, the type information for T is erased and replaced with Object (or a bound, if specified).
Arrays in Java, however, are reifiable types. They know their component type at runtime. Therefore, the JVM can verify that you only put elements of the correct type into the array. If you could write new T[10], at runtime the array would be Object[], and you could put String, Integer, and Date into it simultaneously — which violates the entire concept of type safety.
That is why the compiler gives an error:
\n// ❌ Compilation error: generic array creation\npublic class Box<T> {\n private T[] array = new T[10]; // Cannot create a generic array of T\n}\n\nMethod 1: The simplest — use ArrayList
\n\nMost of the time, you don't actually need an array. ArrayList internally works with Object[] but provides a type-safe interface. This is the ideal solution if you are not fixated on nanosecond-level performance.
import java.util.ArrayList;\nimport java.util.List;\n\npublic class GenericListExample<T> {\n private List<T> list = new ArrayList<>();\n\n public void add(T item) {\n list.add(item);\n }\n\n public T get(int index) {\n return list.get(index);\n }\n\n public int size() {\n return list.size();\n }\n}\n\nPros: full type safety, no warnings, support for dynamic expansion.
\nCons: slight overhead for boxing/unboxing primitives (but for 99% of applications, this is negligible).
Method 2: The classic hack with (T[]) new Object[size]
\n\nIf you really need an array (for example, for performance or compatibility with a legacy API), you can use a type cast. This is safe if you guarantee that the array never leaves the boundaries of your class.
\n\npublic class Stack<T> {\n private T[] elements;\n private int size = 0;\n private static final int DEFAULT_CAPACITY = 10;\n\n @SuppressWarnings("unchecked")\n public Stack() {\n elements = (T[]) new Object[DEFAULT_CAPACITY];\n }\n\n public void push(T item) {\n if (size == elements.length) {\n resize();\n }\n elements[size++] = item;\n }\n\n public T pop() {\n if (size == 0) {\n throw new EmptyStackException();\n }\n T result = elements[--size];\n elements[size] = null; // Help GC\n return result;\n }\n\n private void resize() {\n elements = Arrays.copyOf(elements, elements.length * 2);\n }\n}\n\nImportant: the @SuppressWarnings("uncheck