Generic Data Types

Generics: Enable you to write a placeholder instead of an actual class type.

Limitations:

new T is always wrong.

Type-Erasure: The generic type gets removed when being returned.

Why: Generics let us escape casting hell.

Example:

  1. Interface
public interface Pairable<T> {
  T getFirst();
  T getSecond();
  void changeOrder();
}
  1. Implementation
public class OrderedPair<T> implements Pairable<T> {
  // ... TODO
  public OrderedPair() {
  }
  public T getFirst() {
  }
  public T getSecond() {
  }
}

Example: Implementing getFrequencyOf in the client

public static int getFrequencyOf (BagInterface<String> bag, String needle) {
  // You can't cast arrays, you have to cast reference individually!
  Object[] bagArray = bag.toArray();
  int counter = 0;
  for (Object item : bagArray)
      // Polymorphism:
      // - At runtime, this will execute the String's equals()
      // - At compilation this will be seen as the Object's equals(), but widening means that there is no syntax error.
      if (item.equals(needle))
          counter++;
  return counter;
}

Note/Example: When implementing a method in the client to do something with an interface, make sure you take the interface as a parameter rather than the implementation.

// Algorithm
static void displayBag(BagInterface<String> key) {
  for (Object item : bag.toArray())
      System.out.println(item);
}
// Generic Method of the Algorithm
static<T> void displayBag(BagInterface<T> key) {
  for (T item : bag.toArray())
      System.out.println(item);