Generics
Generics In many situations, we want a certain functionality to work for a variety of types Typical example: we want to be able to store elements of a certain type in a container, say an ArrayList This ability does not pose any special requirements on the type itself RHS – SWC
Generics public class ArrayList { public ArrayList() {…} public void add(Object e) {…} } RHS – SWC
Generics Since all classes inherit from Object, this will work – in principle However, there is nothing to prevent us from storing elements of different types in the same ArrayList Will complicate processing of the elements Risk for errors at run-time RHS – SWC
Generics A better (safer) solution is to use Generics In a generic class, one or more type parameters are included in the definition Example is the well-known ArrayList<E> RHS – SWC
Generics public class ArrayList<E> { public ArrayList() {…} public void add(E e) {…} } E is the type parameter RHS – SWC
Generics When we wish to use the class, we must ”instantiate” it with a concrete type: ArrayList<BankAccount> ArrayList<Car> We can use the ArrayList for all types, BUT we cannot put two objects of different types into the same ArrayList RHS – SWC
Creating a generic class Creating a generic class is almost like creating an ordinary class However, one or more of the types are turned into type parameters Consider a class for storing a pair of objects, which may have different types Pair<String, Car> RHS – SWC
Creating a generic class public class Pair<T,S> { private T first; private S second public Pair(T first, S Second) {...} public T getFirst() {return first;} public S getSecond() {return second;} } RHS – SWC
Creating a generic method An ordinary method inside a class usually does not need a type parameter Type parameter for class is used However, this is not the case for static methods: public static <E> void print(E[] a) RHS – SWC
Creating a generic method When invoking a generic method, we do not need to specify a type parameter: Car[] carList; ArrayUtil.print(carList); The compiler can figure out what the concrete type of the parameter is RHS – SWC
Type constraints Sometimes, we will only allow types that fulfill some properties Consider the min method: public static <E> E min(E a, E b) { if (a < b) return a; else return b; } RHS – SWC
Type constraints The previous code will only work for types that can be compared Type must implement the Comparable interface We must constrain the type parameter to fulfill this property RHS – SWC
Type constraints public static <E extends Comparable> E min(E a, E b) { if (a < b) return a; else return b; } RHS – SWC
Under the hood How does the Java Virtual Machine handle generics…? It substitutes the type variables with a concrete type, depending on the type constraints RHS – SWC
Under the hood public class Pair<T, S> { private T first; private S second public Pair(T first, S Second) {...} public T getFirst() {return first;} public S getSecond() {return second;} } RHS – SWC
Under the hood public class Pair { private Object first; private Object second public Pair(Object first, Object Second) {...} public Object getFirst() {return first;} public Object getSecond() {return second;} } RHS – SWC
Under the hood But will that always work…? Yes, because the compiler has checked that all generic types are used correctly It does however impose some limitations on the code in generic methods: E e = new E(); This is illegal…(why)? RHS – SWC
Under the hood Why does it work like that? Enables pre-generics code to work together with code using generics Does it matter in practice? Not much, but it explains why some perhaps not-so-obvious limitations exist RHS – SWC
Exercises Review: R16.5, R16.7, R16.8 Programming P16.1, P16.2 RHS – SWC