How can you properly create a Java generic array while maintaining type safety?

Due to Java’s generics implementation, code like this results in an error:

public class GenSet<E> {  
    private E a[];  

    public GenSet() {  
        a = new E[INITIAL_ARRAY_LENGTH]; // Error: generic array creation  
    }  
}

How can I implement this correctly while ensuring type safety?

I found a solution on a Java forum that uses reflection:

import java.lang.reflect.Array;  

class Stack<T> {  
    public Stack(Class<T> clazz, int capacity) {  
        array = (T[]) Array.newInstance(clazz, capacity);  
    }  

    private final T[] array;  
}

What’s happening in this approach, and why does it work?

Your forum solution works because Array.newInstance() allows us to bypass the type erasure issue while maintaining type safety.

import java.lang.reflect.Array;

class GenSet {
private E a;

public GenSet(Class<E> clazz, int size) {  
    a = (E[]) Array.newInstance(clazz, size);  
}  

public E get(int index) {  
    return a[index];  
}  

}

:white_check_mark: Why This Works:

  • Array.newInstance(clazz, size) dynamically creates an array of the correct type.

  • Type safety is ensured because the array is instantiated with a runtime type token (Class).

:x: Downside:

Requires passing Class as a parameter when constructing an instance.

Usage Example: GenSet stringSet = new GenSet<>(String.class, 10);

Use an Object Internally and Cast on Retrieval

“A simpler approach is to use an Object array and cast elements when retrieving them.”

class GenSet<E> {  
    private Object[] a;  

    public GenSet(int size) {  
        a = new Object[size];  
    }  

    public void set(int index, E value) {  
        a[index] = value;  
    }  

    @SuppressWarnings("unchecked")
    public E get(int index) {  
        return (E) a[index];  
    }  
}

:white_check_mark: Why This Works:

Java allows arrays of Object, and since all types in Java extend Object, storing elements works fine.

The cast (E) a[index] is safe if used correctly.

:x: Downside:

There is no compile-time guarantee that a[index] is actually of type E (could lead to ClassCastException at runtime).

Usage Example:
GenSet<Integer> intSet = new GenSet<>(10);
intSet.set(0, 42);
Integer val = intSet.get(0);

Since arrays and generics don’t mix well, why not use a List instead?"

import java.util.ArrayList;
import java.util.List;

class GenSet<E> {  
    private List<E> list;  

    public GenSet() {  
        list = new ArrayList<>();  
    }  

    public void add(E element) {  
        list.add(element);  
    }  

    public E get(int index) {  
        return list.get(index);  
    }  
}

:white_check_mark: Why This Works:

ArrayList is inherently generic and avoids type erasure issues with arrays.

Type safety is guaranteed without unchecked casts.

:x: Downside:

Slightly slower than using arrays due to dynamic resizing and additional abstraction.

Usage Example:

GenSet<Double> doubleSet = new GenSet<>();
doubleSet.add(3.14);
Double pi = doubleSet.get(0);Since arrays and generics don’t mix well, why not use a List<E> instead?
import java.util.ArrayList;
import java.util.List;

class GenSet<E> {  
    private List<E> list;  

    public GenSet() {  
        list = new ArrayList<>();  
    }  

    public void add(E element) {  
        list.add(element);  
    }  

    public E get(int index) {  
        return list.get(index);  
    }  
}

:white_check_mark: Why This Works:

ArrayList is inherently generic and avoids type erasure issues with arrays.

Type safety is guaranteed without unchecked casts.

:x: Downside:

Slightly slower than using arrays due to dynamic resizing and additional abstraction.

Usage Example:
GenSet<Double> doubleSet = new GenSet<>();
doubleSet.add(3.14);
Double pi = doubleSet.get(0);