Java Generics
Type-safe programming with parameterized types
🎯 What are Generics?
Generics enable types to be parameters when defining classes, interfaces, and methods. They provide compile-time type safety and eliminate the need for casting.
// Generic ArrayList - type safe
ArrayList<String> names = new ArrayList<>();
names.add("John");
String name = names.get(0); // No casting needed
Output:
names: ["John"]
name: "John" (String type guaranteed)
Generic Features
Generic Classes
Classes with type parameters
class Box<T> {
private T item;
}
Generic Methods
Methods with type parameters
public <T> void swap(T[] array, int i, int j)
Bounded Types
Restrict generic types
class NumberBox<T extends Number>
Wildcards
Flexible type matching
List<? extends Number> numbers
🔹 Generic Class Example
Creating a generic class that can work with any type:
// Generic class definition
class Container<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
// Using the generic class
Container<String> stringBox = new Container<>();
stringBox.setItem("Hello");
String message = stringBox.getItem();
Container<Integer> intBox = new Container<>();
intBox.setItem(42);
Integer number = intBox.getItem();
Output:
message: "Hello"
number: 42
🔹 Generic Methods
Methods that can work with different types:
public class GenericMethods {
// Generic method to swap array elements
public static <T> void swap(T[] array, int i, int j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
// Generic method to find maximum
public static <T extends Comparable<T>> T findMax(T[] array) {
T max = array[0];
for (T item : array) {
if (item.compareTo(max) > 0) {
max = item;
}
}
return max;
}
}
// Usage
String[] words = {"apple", "banana", "cherry"};
GenericMethods.swap(words, 0, 2);
String maxWord = GenericMethods.findMax(words);
Output:
After swap: ["cherry", "banana", "apple"]
maxWord: "cherry"
🔹 Wildcards in Generics
Using wildcards for flexible generic types:
import java.util.*;
public class WildcardExample {
// Upper bounded wildcard
public static double sumNumbers(List<? extends Number> numbers) {
double sum = 0.0;
for (Number num : numbers) {
sum += num.doubleValue();
}
return sum;
}
// Lower bounded wildcard
public static void addNumbers(List<? super Integer> numbers) {
numbers.add(1);
numbers.add(2);
numbers.add(3);
}
}
// Usage
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
List<Double> doubles = Arrays.asList(1.1, 2.2, 3.3);
double intSum = WildcardExample.sumNumbers(integers);
double doubleSum = WildcardExample.sumNumbers(doubles);
Output:
intSum: 15.0
doubleSum: 6.6