Why Generics, and How to Declare One
Suppose we want a growable collection of Student, where Student has an id, a name, and a gpa. Here is a non-generic DynamicArray, storing int:
public class DynamicArray {
private int[] arr;
private int size;
public void add(int value) {
if (size == arr.length) {
grow();
}
arr[size] = value;
size++;
}
public int get(int index) {
return arr[index];
}
public DynamicArray() {
arr = new int[10];
size = 0;
}
}
Solution
One way is to copy the class and retype it, StudentDynamicArray, with every int replaced by Student. The logic for growing and adding is identical to the original; only the element type differs. A bug fix has to be applied once per copy, and a new element type means another copy.
The other way is to store Object instead of int. One class handles any element type, but every get needs a cast to use the result, and nothing stops add from accepting the wrong type. The mistake compiles and only shows up as a ClassCastException later, at runtime.
A generic DynamicArray<T> avoids both costs: one class, and the compiler still knows the element type, so get needs no cast and adding the wrong type is a compile error.
Solution
public class DynamicArray<T> {
private T[] arr;
private int size;
public void add(T value) {
if (size == arr.length) {
grow();
}
arr[size] = value;
size++;
}
public T get(int index) {
return arr[index];
}
@SuppressWarnings("unchecked")
public DynamicArray() {
arr = (T[]) new Object[10];
size = 0;
}
}
new T[10] does not compile because Java erases the type parameter: at runtime, T is not known, but creating an array requires a concrete element type. The fix is to create an Object[] and cast it to T[]. The cast is unchecked, but it is safe here because arr is private and every entry point (add, get) is typed to T.
Solution
Generics only work with reference types. A type parameter erases to Object, and an int is not a reference, so there is no way to store a bare int where a T is expected. Use the wrapper class instead: DynamicArray<Integer>. Autoboxing and unboxing convert between int and Integer automatically at the call sites, so scores.add(5) and int x = scores.get(0) still work.