How can I create a generic array in Java?
In Java, due to type-erasure and array covariance, you can’t directly create a “new” array of a parameterized type (e.g., new T[]) in the usual way. Instead, you have to rely on a couple of well-known workarounds. Below are some approaches along with best practices and caveats.
1. Casting from Object[]
A common technique is to create an Object[] first and then cast it to your generic type:
public class MyGenericClass<T> { private T[] elements; // Example: pass desired size @SuppressWarnings("unchecked") public MyGenericClass(int size) { // Create an array of Objects elements = (T[]) new Object[size]; } public void setElement(int index, T value) { elements[index] = value; } public T getElement(int index) { return elements[index]; } }
-
Why
@SuppressWarnings("unchecked")?
Because of type erasure, the cast(T[]) new Object[size]triggers an unchecked warning. You’re essentially telling the compiler, “Trust me, I’ll only putTelements in here.” -
Caution
This array is still technically anObject[]at runtime. If you accidentally store the wrong type in it (via raw or unsafe operations), you might not catch the error until aClassCastExceptionoccurs at runtime.
2. Using Array.newInstance(Class<?>, int length)
If you know the Class object for the type T, you can use reflection:
import java.lang.reflect.Array; public class MyGenericClass<T> { private T[] elements; @SuppressWarnings("unchecked") public MyGenericClass(Class<T> clazz, int size) { // Use reflection elements = (T[]) Array.newInstance(clazz, size); } public void setElement(int index, T value) { elements[index] = value; } public T getElement(int index) { return elements[index]; } }
- Pros
- Creates a “proper” array of the specified runtime type. This means if
clazzisString.class, then you really do get aString[]at runtime.
- Creates a “proper” array of the specified runtime type. This means if
- Cons
- You must pass the
Class<T>into the constructor, which can be slightly more verbose. - Still subject to the same generics limitations at compile time.
- You must pass the
3. Use a List<T> Instead
Often, it’s more idiomatic to use a generic List<T> (e.g., ArrayList<T>) rather than manually handling arrays:
public class MyGenericClass<T> { private List<T> elements; public MyGenericClass() { elements = new ArrayList<>(); } public void add(T value) { elements.add(value); } public T get(int index) { return elements.get(index); } }
- Pros
- Simpler syntax, no casting or suppressed warnings.
- Dynamic resizing, which is often more convenient than fixed-size arrays.
- Cons
- Not suitable if you specifically need a low-level array (e.g., for certain performance or memory constraints, or interop with legacy APIs).
Key Takeaways & Best Practices
- Type Erasure: Remember that Java generics exist only at compile time. At runtime, a
T[]is effectively the same as anObject[]unless you use reflection (Array.newInstance). - Unchecked Warnings: Casting an
Object[]toT[]requires@SuppressWarnings("unchecked"). Use this sparingly and document why it’s safe. - Preferred Approach: Often, using a collection class like
ArrayList<T>is more flexible and less error-prone unless there’s a specific requirement for arrays.
Sharpen Your Java Skills
For a deeper dive into Java best practices, data structures, and advanced generics, here are some recommendations from DesignGurus.io:
-
Grokking Data Structures & Algorithms for Coding Interviews
Perfect for mastering arrays, lists, trees, graphs, and more, giving you a strong foundation for any coding challenge. -
Grokking the Coding Interview: Patterns for Coding Questions
Learn the key patterns behind interview questions, so you can quickly identify optimal solutions in Java or any other language.
Ready for hands-on practice and expert feedback? Consider a Mock Interview with ex-FAANG engineers, and explore the DesignGurus YouTube Channel for tutorials and tips on system design, coding patterns, and more.
Bottom Line:
- Directly writing
new T[size]isn’t possible in Java because of type erasure. - The common workarounds include
(T[]) new Object[size](with a suppressed warning) or usingArray.newInstance(clazz, size)if you have aClass<T>object. - For many use cases, a
List<T>(likeArrayList<T>) is a cleaner and more flexible alternative to managing raw arrays.