1. Introduction
Generics allow classes, interfaces, and methods to be written with type parameters, letting the same code work with different data types while the compiler enforces type safety. Before generics (pre-Java 5), collections stored everything as Object, requiring explicit casts that could fail at runtime with a ClassCastException; generics push that type checking to compile time instead.
Cricket analogy: Before DRS, umpires guessed lbw calls and got them wrong on the field, like pre-Java-5 code casting Objects and blowing up at runtime; generics are like DRS, catching the wrong call before it's locked in.
A common example is java.util.List<String>, which guarantees at compile time that only String objects can be added to and retrieved from that list, eliminating the need for explicit casting when reading elements out of it.
Cricket analogy: A team sheet that only allows specialist batsmen in the top order guarantees the captain never has to double-check who's walking out to bat, the same way List<String> guarantees every element is already a String.
2. Syntax
// Generic class with a type parameter T
class Box<T> {
private T content;
public void set(T content) { this.content = content; }
public T get() { return content; }
}
// Bounded type parameter — T must extend Number
class NumericBox<T extends Number> {
private T value;
public double asDouble() { return value.doubleValue(); }
}
// Generic method
public static <T> T firstElement(List<T> list) {
return list.get(0);
}
// Wildcards
List<? extends Number> readOnlyNumbers; // can read Numbers, can't add
List<? super Integer> writableInts; // can add Integers safely3. Explanation
A type parameter such as <T> acts as a placeholder for an actual type supplied when the generic class or method is used, e.g. Box<String> or Box<Integer>. This gives compile-time type safety: the compiler rejects attempts to insert the wrong type, and no explicit cast is required when retrieving elements, because the compiler already knows the exact type.
Cricket analogy: A kit bag labeled 'Box<Bat>' versus 'Box<Ball>' means the equipment manager instantly knows what's inside without opening it, just like Box<String> vs Box<Integer> tells the compiler the exact contents without a cast.
Bounded type parameters, written as <T extends SomeType>, restrict T to SomeType or its subtypes, which is useful when the generic code needs to call methods defined on that bound (e.g. calling doubleValue() requires T to extend Number). Wildcards (?) are used in method parameters to express flexibility: <? extends T> accepts T or any subtype (read-only, 'producer'), while <? super T> accepts T or any supertype (write-safe, 'consumer') — this is often summarized by the mnemonic PECS ('Producer Extends, Consumer Super').
Cricket analogy: Restricting a bowling attack selector to '<T extends FastBowler>' means only pacers who can genuinely clock 140kmh get picked, just as a bounded type parameter restricts T to types with the needed capability like doubleValue().
Exam trap: type erasure. Generic type information exists only at compile time; the compiler erases it and replaces type parameters with their bound (Object if unbounded) in the compiled bytecode. This means you cannot do new T(), cannot use instanceof with a parameterized type like obj instanceof List<String>, and at runtime, via reflection, list.getClass() returns java.util.ArrayList regardless of whether it was declared List<String> or List<Integer> — the generic type info is not available at runtime.
4. Example
import java.util.ArrayList;
import java.util.List;
public class GenericsDemo {
static class Box<T> {
private T content;
public void set(T content) { this.content = content; }
public T get() { return content; }
}
static <T extends Number> double sumAsDouble(List<T> numbers) {
double sum = 0.0;
for (T n : numbers) {
sum += n.doubleValue();
}
return sum;
}
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.set("Hello Generics");
String value = stringBox.get(); // no cast needed
System.out.println(value);
List<Integer> ints = new ArrayList<>();
ints.add(10);
ints.add(20);
ints.add(30);
System.out.println("Sum: " + sumAsDouble(ints));
// Type erasure demonstration
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
System.out.println("Same runtime class? " + (strList.getClass() == intList.getClass()));
}
}5. Output
Hello Generics
Sum: 60.0
Same runtime class? true6. Key Takeaways
- Generics provide compile-time type safety and eliminate the need for explicit casts.
- A type parameter like <T> is a placeholder replaced by an actual type when the generic is used.
- Bounded type parameters (<T extends Number>) restrict what types can be used and what methods are callable.
- Wildcards <? extends T> and <? super T> add flexibility to method parameters (PECS: Producer Extends, Consumer Super).
- Type erasure removes generic type information at compile time — it is not available at runtime via reflection.
- Because of type erasure,
new T()andinstanceof List<String>are not allowed.
Practice what you learned
1. What is the main benefit of using generics in Java?
2. What does type erasure mean in the context of Java generics?
3. What does `<T extends Number>` mean in a generic class declaration?
4. Which wildcard would you use for a list you only read from and want to accept any subtype of Number?
5. Due to type erasure, which of the following is NOT allowed in Java generics?
Was this page helpful?
You May Also Like
Interfaces in Java
Learn how Java interfaces define a contract of behavior, support multiple inheritance of type, and how default/static methods work since Java 8.
Collections Framework in Java
Understand the Java Collections Framework hierarchy — Collection vs Map, List/Set/Queue interfaces, and how to pick the right implementation.
ArrayList in Java
Learn how ArrayList works internally, its time complexity, and when to use it over arrays or LinkedList.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics