Lesson 22 of 25

Generics

Generic Classes and Methods

Generics let you write classes and methods that work with any type while maintaining type safety at compile time.

Example
// Generic class
public class Box<T> {
    private T content;

    public void put(T item) {
        this.content = item;
    }

    public T get() {
        return content;
    }
}

// Usage
Box<String> stringBox = new Box<>();
stringBox.put("Hello");
String s = stringBox.get(); // No casting needed

Box<Integer> intBox = new Box<>();
intBox.put(42);
int n = intBox.get();

// Generic method
public static <T> void printArray(T[] array) {
    for (T item : array) {
        System.out.print(item + " ");
    }
}

Bounded Generics and Wildcards

Use bounds to restrict what types a generic can accept. Wildcards provide flexibility when using generic types.

Example
// Upper bound — T must extend Comparable
public static <T extends Comparable<T>> T findMax(T[] arr) {
    T max = arr[0];
    for (T item : arr) {
        if (item.compareTo(max) > 0) {
            max = item;
        }
    }
    return max;
}

// Wildcards
public static double sum(List<? extends Number> list) {
    double total = 0;
    for (Number n : list) {
        total += n.doubleValue();
    }
    return total;
}

sum(List.of(1, 2, 3));       // works with Integer
sum(List.of(1.5, 2.5));      // works with Double