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 