Why Generics?
Our DynamicArray has one limitation: it only holds int. That was fine while we were learning how it works. But when we build data structures for real use, we want them to hold any type of element.
Suppose we are building a course roster. The thing we want to store is a student, with an ID, a name, and a GPA:
public class Student {
private int id;
private String name;
private double gpa;
public Student(int id, String name, double gpa) {
this.id = id;
this.name = name;
this.gpa = gpa;
}
public int getId() { return id; }
public String getName() { return name; }
public double getGpa() { return gpa; }
}
Now we would like a roster: a growable collection of Students. We already built a growable collection. But ours stores int, and there is no way to put a Student into an int[].
Copying the class for each type
One option is to write a second class. Call it StudentDynamicArray, or maybe Roster, which is the more accurate name. It is the same as DynamicArray except that every int element becomes a Student:
public class StudentDynamicArray {
private Student[] arr; // was int[]
private int size;
public void add(Student value) { ... } // was int value
public Student get(int index) { ... } // was int
// ...and so on, the same logic, retyped
}
This works. But we copied the entire class to change one thing, the element type. And when we want a dynamic array of something else, a dynamic array of names (String), a dynamic array of scores (double), we would copy it again. The logic for growing, adding, and removing is identical every time. Only the element type differs.
Duplicated code like this is expensive to maintain. Fix a bug in one copy and you have to remember to fix it in all the others. We should not have to rewrite the same data structure once per type.
Writing the collection once
What we really want is to write the collection once, leaving a blank where the element type goes, and fill in that blank when we use it:
- a
DynamicArrayofStudent, - a
DynamicArrayofString, - a
DynamicArrayof anything.
One class that works for any element type. That blank is called a type parameter, and the Java mechanism that gives us type parameters is generics.
There is another approach that looks simpler than generics. It is to store Object instead of a specific type. We will look at that one first.