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];
}
}
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).
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];
}
}
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.
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);
}
}
Why This Works:
ArrayList is inherently generic and avoids type erasure issues with arrays.
Type safety is guaranteed without unchecked casts.
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);
}
}
Why This Works:
ArrayList is inherently generic and avoids type erasure issues with arrays.
Type safety is guaranteed without unchecked casts.
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);