Memra

Why generics & generic classes

Type parameters give you compile-time type safety and remove casts — the TwoTuple<A,B> the Greenhouse project uses.

The problem generics solve

Before generics (Java 1.5), a container held Object, so the compiler could not tell *what* you put in it. You paid for that on the way out, with a cast that the compiler trusted blindly:

List list = new ArrayList();   // raw type — holds Object
list.add("hello");
list.add(42);                  // compiles! nothing stops you
String s = (String) list.get(1); // compiles, then THROWS ClassCastException at runtime

The bug (42 is not a String) is invisible until the program runs. Generics move that check to compile time. You tell the compiler the element type once, and it enforces it everywhere:

List<String> list = new ArrayList<>();
list.add("hello");
list.add(42);                  // COMPILE ERROR — caught immediately
String s = list.get(0);        // no cast needed — return type is already String

Two wins: type safety (the wrong type is rejected at compile time) and no casts (get returns the parameter type directly). The <> on the right is the *diamond operator* — the compiler infers the type argument from the left-hand declaration.

Writing a generic class

You parameterise a class by listing type parameters in angle brackets after the class name. Inside the class, those names stand in for whatever concrete type a caller supplies. Here is the TwoTuple<A,B> the Greenhouse control system uses to return a pair of values:

public class TwoTuple<A, B> {
    public final A first;
    public final B second;

    public TwoTuple(A a, B b) {
        first = a;
        second = b;
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ")";
    }
}

A and B are not real types — they are placeholders. When you write new TwoTuple<String, Integer>("id", 7), the compiler treats first as a String and second as an Integer for that object. A different call, new TwoTuple<Event, Long>(e, time), reuses the *same class* with different types.

Naming convention. Single uppercase letters: T (type), E (element), K/V (key/value), A/B (when you need two unrelated types). Multiple parameters are comma-separated.

Why not just use Object?

You *could* write a class with Object first; Object second; — but then every caller must cast on the way out and the compiler cannot stop them mixing types. Generics give you exactly one declaration site and many type-checked use sites.

NORMAL ~/memra/learn/comp-308/why-generics-generic-classes utf-8 LF