Generics
On this page
Letβs dive into Generics, one of the most important and sometimes misunderstood features in Java.
Generics bring type safety, code reusability, and readability to Java β especially useful when dealing with collections, APIs, or building frameworks.
𧬠Java Generics β The Power of Type Safety
π What Are Generics?
Generics allow you to write code that works with any type, while maintaining compile-time type checking.
Instead of writing different versions of the same code for different types (like Integer
, String
, etc.), you write it once using type parameters like <T>
.
β Why Use Generics?
Feature | Benefit |
---|---|
Type safety | Errors caught at compile-time (no ClassCastException at runtime) |
Code reusability | One method or class for multiple data types |
Eliminate casting | Avoid manual type conversion |
Clean, maintainable | Improves API and code readability |
β Real-world: Generics are used everywhere β in Collections, Streams, custom libraries, and frameworks like Spring and Hibernate.
π¦ Without vs With Generics
π΄ Without Generics (Old style):
List list = new ArrayList();
list.add("hello");
String str = (String) list.get(0); // manual cast
β With Generics:
List<String> list = new ArrayList<>();
list.add("hello");
String str = list.get(0); // no cast needed β
π― Generic Class Example
public class Box<T> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; }
public static void main(String[] args) {
Box<Integer> intBox = new Box<>();
intBox.set(100);
Box<String> strBox = new Box<>();
strBox.set("Java");
System.out.println(intBox.get()); // 100
System.out.println(strBox.get()); // Java
}
}
π― Generic Method Example
public class Printer {
public static <T> void print(T data) {
System.out.println(data);
}
public static void main(String[] args) {
print("Hello");
print(123);
print(3.14);
}
}
<T>
before return type tells the compiler it’s a generic method.
π Multiple Type Parameters
public 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; }
}
π Bounded Type Parameters
Use extends
to restrict what type can be used with a generic.
public class MathUtils<T extends Number> {
public double doubleValue(T num) {
return num.doubleValue();
}
}
Now you can only use Integer
, Double
, Float
, etc.
π Wildcards (?
, extends
, super
)
Syntax | Meaning |
---|---|
<?> | Unknown type |
<? extends Number> | Accepts Number or any subclass |
<? super Integer> | Accepts Integer or any superclass |
π§ Example:
public static void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
Use wildcards when you’re reading, not modifying the list.
π§ Common Interview Q: Why no List<T>[]
?
Java doesnβt allow generic array creation due to type erasure. You canβt do:
List<String>[] list = new ArrayList<String>[10]; // Compile error β
But you can use:
List<?>[] list = new ArrayList<?>[10]; // Warning suppressed
π§ Summary Table
Feature | Purpose |
---|---|
<T> | Declare generic type |
<T extends Number> | Restrict to specific types |
List<?> | Accept any list |
<? extends T> | For reading from structure |
<? super T> | For writing to structure |
Generics + Collections | Type-safe data handling |
π Homework for Students
Task 1: Create a generic class Container<T>
with methods:
void add(T item)
T get(int index)
Test it with both Integer
and String
types.
Task 2: Write a method:
<T extends Comparable<T>> T findMax(List<T> list)
Which returns the largest element in the list.
Task 3: Use wildcard:
Write a method that takes a List<?>
and prints all elements, regardless of type.
Task 4: Create a generic Pair<K, V>
class and print key-value pairs of type:
String, Integer
String, String
Would you like to move into Lambda Expressions & Streams next, which build beautifully on generics and are core to modern Java (Java 8+)?