Skip to main content

Generics

Type Parameter

<T> is Type parameter

public class Printer <T> {
T val;
}

Bounded Generic

<T extends Animal> is bounded generic

public class Printer <T extends Animal> {
T val;
}
  • Animal can be a class or Interface. Use extends for interfaces. No such thing as <T implements Animal>

Multiple Bounded Generic

<T extends Animal & Serializable> is multiple bounded generic

public class Printer <T extends Animal & Serializable> {
T val;
}
  • With multiple bounds there can be atmost 1 class
  • The class should be the 1st entry. <T extends Serializable & Animal>, listing Animal class as the second item would lead to compilation error

Recursive Type

class Fruit <T extends Fruit<T>> is recursive type

class Fruit <T extends Fruit<T>> implements Comparable<T> {
T size;

@override public int compareTo(T other) {
return size.compareTo(other.getSize()) // .getSize() is available because T extends Fruit<T>
}
}
  • A recursive type is one that includes a function that uses that type itself as a type for some argument or its return value.

  • Explained beautifuly in this stack overflow answer.

Generic Method

public static <T> void print(T toPrint) {
System.out.println(toPrint);
}
  • Type Parameter should be specified within diamond brackets before the return type.

Wildcard (?) in Generic Method

Call to print will fail as it expects a List<Object> which is not the same as List<Animal>

public static void main(String args[]) {
List<Animal> animals = Arrays.asList(new Cat(), new Dog());
print(animals)
}

public static void print(List<Object> toPrint) {
for (Object obj: toPrint) {
System.out.println(toPrint);
}
}

We can use the wildcard ? to specify list of unknown type List<?>

public static void main(String args[]) {
List<Animal> animals = Arrays.asList(new Cat(), new Dog());
print(animals)
}

public static void print(List<?> toPrint) { // Compiler can assume ? is atleast of base type Object.
for (Object obj: toPrint) {
System.out.println(toPrint);
}
}

Bounded Wildcard in Generic Method

<? extends Animal> is a upper bounded wildcard

public static void main(String args[]) {
List<Animal> animals = Arrays.asList(new Cat(), new Dog());
print(animals)
}

public static void print(List<? extends Animal> toPrint) { // You can pass the type and subtypes - List<Animal>, List<Cat>, List<Dog> but not List<Object>
for (Object obj: toPrint) {
System.out.println(toPrint.toPrettyString()); // Gives access to .toPrettyString() method in Animal
}
toPrint.add(new Cat()) // Compile error: Cannot infer what type list is, could be a List<Dog>
}

<? super Cat> is a lower bounded wildcard

public static void main(String args[]) {
List<Animal> animals = Arrays.asList(new Cat(), new Dog());
addCat(animals) // It works, I should be able to add a Cat intop a list of Animals
}

public static void addCat(List<? super Cat> animals) { // You can pass the type and supertypes - List<Cat>, List<Animal>, List<Object>. You cant pass a List<Dog>
toPrint.add(new Cat())
}