Lesson 30 / 38

Generics Basics

Add type parameters to your own classes and methods so the compiler checks every use and you never cast when reading values back.

A generic class

A type parameter <T> is a placeholder the caller fills in. The compiler then checks every use, so you never cast when reading back.

class Box<T> {
    private T item;
    void put(T item) { this.item = item; }
    T get() { return item; }
}

Box<String> b = new Box<>();
b.put("hi");
String s = b.get();   // no cast

Generic methods

A single method can declare its own type parameter, independent of any class it lives in. The compiler infers T from the argument you pass.

static <T> T firstOf(List<T> items) {
    return items.get(0);
}

String s = firstOf(List.of("a", "b"));   // T inferred as String
Integer n = firstOf(List.of(1, 2, 3));   // T inferred as Integer

Bounded type parameters

<T extends Comparable<T>> restricts T to types that are comparable, so the method body can call compareTo on values of type T. extends here means "is a subtype of" for both classes and interfaces.

static <T extends Comparable<T>> T max(T a, T b) {
    return a.compareTo(b) >= 0 ? a : b;
}

max(3, 7);        // 7
max("pear", "fig"); // "pear"