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
Recommended Courses
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.