Generics in Java: Type-Safe and Reusable Collections
✅ What Are Generics in Java?
Generics allow you to define classes, interfaces, and methods with type parameters.
Without Generics (Old Style):
List list = new ArrayList();
list.add("Java");
String s = (String) list.get(0); // Need to cast manually
With Generics:
List<String> list = new ArrayList<>();
list.add("Java");
String s = list.get(0); // No casting needed
🔧 Why Use Generics?
Benefit |
Description |
Type safety |
Catch errors at compile-time |
No casting |
No need to cast when getting elements |
Code reuse |
Write flexible, reusable code |
🔹 Using Generics with Collections
List Example:
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
for (int num : numbers) {
System.out.println(num);
}
Set Example:
Set<String> names = new HashSet<>();
names.add("Alice");
names.add("Bob");
Map Example (Two type parameters):
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
🧱 Defining Your Own Generic Class
class Box<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
Using Box:
Box<String> stringBox = new Box<>();
stringBox.set("Hello");
System.out.println(stringBox.get());
Box<Integer> intBox = new Box<>();
intBox.set(123);
System.out.println(intBox.get());
🧠 Common Generic Syntax
Syntax |
Meaning |
<T> |
Generic type T |
<K, V> |
Key and Value type (e.g., for Map) |
<T extends Number> |
Upper bound – T must be a Number |
<?> |
Wildcard – unknown type |
🌀 Wildcards in Generics
Unbounded Wildcard:
List<?> list = new ArrayList<String>();
Bounded Wildcards:
// Upper bound (read-only)
List<? extends Number> numbers = new ArrayList<Integer>();
// Lower bound (write allowed)
List<? super Integer> list = new ArrayList<Number>();