Java Generics
Why Generics?
Generics enable you to write classes and methods that work with any type while providing compile-time type safety. Without generics you'd need casts everywhere and could get ClassCastException at runtime.
| Without Generics | With Generics |
|---|---|
| No type checking at compile time | Type errors caught at compile time |
| Requires explicit casting | No casting needed |
| Risk of ClassCastException at runtime | Type-safe — no runtime surprises |
// Generic class — T is a type parameter (placeholder)
class Box<T> {
private T value;
public Box(T value) { this.value = value; }
public T getValue() { return value; }
public void setValue(T value) { this.value = value; }
@Override
public String toString() { return "Box[" + value + "]"; }
}
// Generic class with two type parameters
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) { this.key = key; this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
@Override
public String toString() { return "(" + key + ", " + value + ")"; }
}
public class Generics {
// Generic method
public static <T> void printArray(T[] arr) {
for (T item : arr) System.out.print(item + " ");
System.out.println();
}
public static void main(String[] args) {
Box<Integer> intBox = new Box<>(42);
Box<String> strBox = new Box<>("Hello");
System.out.println(intBox); // Box[42]
System.out.println(strBox); // Box[Hello]
Pair<String, Integer> p = new Pair<>("age", 30);
System.out.println(p); // (age, 30)
Integer[] nums = {1, 2, 3, 4, 5};
String[] strs = {"a", "b", "c"};
printArray(nums); // 1 2 3 4 5
printArray(strs); // a b c
}
}
Bounded Type Parameters & Wildcards
import java.util.*;
public class BoundedGenerics {
// Upper bound: T must be Number or a subclass
public static <T extends Number> double sum(List<T> list) {
double total = 0;
for (T item : list) total += item.doubleValue();
return total;
}
// Wildcard ? — unknown type
// ? extends Number — upper bounded wildcard (read-only)
public static void printNumbers(List<? extends Number> list) {
for (Number n : list) System.out.print(n + " ");
System.out.println();
}
// ? super Integer — lower bounded wildcard (write-friendly)
public static void addIntegers(List<? super Integer> list) {
list.add(1);
list.add(2);
list.add(3);
}
public static void main(String[] args) {
List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5);
List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);
System.out.println(sum(ints)); // 15.0
System.out.println(sum(doubles)); // 6.6
printNumbers(ints); // 1 2 3 4 5
printNumbers(doubles); // 1.1 2.2 3.3
List<Number> numbers = new ArrayList<>();
addIntegers(numbers);
System.out.println(numbers); // [1, 2, 3]
}
}
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.