We want to build our own data structures (e.g., a list, a stack, a queue)
StringsIntegersStudentsDo we need to write a separate class for every type?
A Box that holds a String item:
public class StringBox {
private String item;
public StringBox(String item) { this.item = item; }
public String getItem() { return item; }
}A Box that holds an Integer item:
public class IntegerBox {
private Integer item;
public IntegerBox(Integer item) { this.item = item; }
public Integer getItem() { return item; }
}Polymorphism (“many forms”): the same code can work with values of different types
Java supports a few kinds of polymorphism:
Shape s = new Square(2.0);
System.out.println(s.area());
s = new Circle(1.0);
System.out.println(s.area());Shape), many actual object typesarea() method at runtimeObjectEvery class in Java inherits from Object, so…
public class ObjectBox {
private Object item;
public ObjectBox(Object item) { this.item = item; }
public Object getItem() { return item; }
}One class that can hold anything!
ObjectObjectBox box = new ObjectBox("hello");
String s = (String) box.getItem(); // need a cast
Integer n = (Integer) box.getItem(); // compiles!
// ClassCastException at runtimepublic class Box<T> {
private T item;
public Box(T item) { this.item = item; }
public T getItem() { return item; }
}<T> declares a type parameter named TT is a placeholder for a real type, chosen when the class is usedT anywhere you’d use a type: instance variables, parameters, return types, local variablesType parameters are usually a single uppercase letter (but they can be anything, this is just a convention):
T – TypeE – Element (used by Java collections)K, V – Key and Value (used in maps)N – NumberProvide the actual type in angle brackets:
Generics only work with objects, not primitive types
Use the wrapper classes:
| Primitive | Wrapper |
|---|---|
int |
Integer |
double |
Double |
char |
Character |
boolean |
Boolean |
public class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}Declare all types when instantiating a new object:
(E[]) new Object[10]?new E[10] – the actual type of E is not known at runtime (type erasure)Object array and cast it to E[]Es into the arrayA single method (not part of a generic class) can also have its own type parameter:
The method can then be used with different types:
Sometimes we need T to have certain methods
public static <T extends Comparable<T>> T max(T a, T b) {
if (a.compareTo(b) > 0) {
return a;
}
return b;
}T extends Comparable<T>: T must be a type that can be comparedcompareTo on T valuesmax("apple", "banana") and max(3, 7) both workInterfaces can be generic too
The type parameter needs to match:
You’ve already used one: Comparable<T>
MyList<Student> tells the reader exactly what’s inside// Without generics
ObjectBox box = new ObjectBox("hi");
Integer n = (Integer) box.getItem(); // crashes when run
// With generics
Box<String> box = new Box<>("hi");
Integer n = box.getItem(); // won't compileIt’s always better to find a bug before the program runs
ArrayList<String> names = new ArrayList<>();
HashMap<String, Integer> ages = new HashMap<>();
ArrayDeque<Integer> stack = new ArrayDeque<>();java.util uses genericsWrite a generic class called Duo<T> that holds two items of the same type, with the following public methods:
first and second (both of type T)getFirst() and getSecond() return the itemsswap() swaps the two items (returns nothing)toString() returns the items in the format (first, second)Submit your Duo.java file to gradescope
public class Duo<T> {
private T first;
private T second;
public Duo(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() { return first; }
public T getSecond() { return second; }
public void swap() {
T temp = first;
first = second;
second = temp;
}
public String toString() {
return "(" + first + ", " + second + ")";
}
}Note the local variable temp has type T
<T>)new T[] – use (T[]) new Object[n]<T extends Comparable<T>>) let us require certain methods