Generics
Java Generics — type parameters, bounded wildcards, type erasure, and how generics make collections and APIs type-safe.
Last reviewed: January 2025
🔍 What Is It?
Generic Class:
public class Box<T> {
private T value;
public Box(T value) { this.value = value; }
public T get() { return value; }
}
Box<String> stringBox = new Box<>("hello");
Box<Integer> intBox = new Box<>(42);Generic Method:
public <T> List<T> repeat(T item, int times) {
List<T> result = new ArrayList<>();
for (int i = 0; i < times; i++) result.add(item);
return result;
}Bounded Type Parameters:
- →
<T extends Comparable<T>>— T must implement Comparable - →
<T extends Number & Serializable>— T must extend Number AND implement Serializable - →
<? extends Animal>— wildcard: any Animal subtype (read-only) - →
<? super Dog>— wildcard: Dog or any supertype (write-only)
Type Erasure:
Generics are a compile-time feature only. At runtime, List<String> and List<Integer> are both just List. Type information is erased. This is why you cannot do: new T() or T.class.
PECS Rule (Producer Extends, Consumer Super):
- →Use
<? extends T>when you read from a collection (producer) - →Use
<? super T>when you write to a collection (consumer)
🎯 Why Do We Need It?
Before generics (Java 1.4):
List names = new ArrayList();
names.add("Alice");
names.add(42); // accidentally added wrong type!
String name = (String) names.get(0); // cast required
String bad = (String) names.get(1); // ClassCastException at runtime!With generics:
List<String> names = new ArrayList<>();
names.add("Alice");
names.add(42); // COMPILE ERROR — caught at compile time!
String name = names.get(0); // no cast neededGenerics move type errors from runtime to compile time — much better.
🏗️ What Happens in Real Projects?
Generics are everywhere in enterprise Java:
- →All collections: List<Order>, Map<String, User>, Set<Permission>
- →Repository pattern: Repository<T, ID>
- →Service responses: ApiResponse<T>
- →Result types: Optional<T>, CompletableFuture<T>
- →Spring's ResponseEntity<T>, Page<T>
⚙️ How It Works
Type Erasure in Detail:
The compiler replaces generic types with their bounds (or Object if unbounded):
// Source code
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0);
// After erasure (what JVM sees)
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0); // compiler inserts castThis is why:
- →Cannot create generic arrays: new T[10] is illegal
- →Cannot use instanceof with generics: list instanceof List<String> is illegal
- →Cannot get the generic type at runtime without passing Class<T>
💻 Example
Generics in Enterprise Code — Practical generic patterns for reusable, type-safe enterprise components.
🤔 Common Confusions
❓ Why can I not create a generic array (new T[])?
Due to type erasure, T is not known at runtime. Arrays require the actual type at creation time (the JVM needs to know what type to store for array covariance checking). Since T is erased to Object at runtime, new T[] would create an Object[] which could cause heap pollution. Use List<T> instead of T[] in generic code.
❓ What is the difference between <T extends Animal> and <? extends Animal>?
<T extends Animal> is a bounded type parameter — T is a named type variable you can use throughout the method signature and body. <? extends Animal> is a wildcard — you cannot name the specific type, and you cannot add elements to a List<? extends Animal> (because the compiler does not know the exact type). Use T when you need to reference the type multiple times; use ? when you only need to read.
🚨 Common Production Issues
Raw types in legacy code — using List instead of List<T> disables type checking. The compiler warns about this. Gradually add type parameters when maintaining legacy code.
Unchecked cast warnings — casting to generic types (List<String>) is unchecked because of erasure. Suppress with @SuppressWarnings("unchecked") only when you are certain it is safe.
✅ Best Practices
Always use generic types — never use raw types like List, Map.
Apply PECS: <? extends T> for reading, <? super T> for writing.
Use type tokens (Class<T>) when you need the type at runtime.
Prefer List<T> over T[] in generic code.
Use bounded type parameters (<T extends Comparable<T>>) to enable operations on T.
🏛️ Architect's Note
Generics are the foundation of reusable enterprise components. Generic repositories, generic service interfaces, generic response wrappers — these patterns eliminate boilerplate and ensure type safety across your entire codebase. Spring Data's JpaRepository<T, ID> is the canonical example: one interface definition provides type-safe data access for every entity.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
Core Java Interview Prep
Practice interview questions that connect directly to this technology track.
↗ Where this topic fits
Core Java Technology Guide
Return to the Core Java learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Core Java learning path
Browse the full Core Java topic collection and learning order on SplashRide.
Core Java Interview Prep
Practice Core Java interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
List
The List interface — ordered, indexed, allows duplicates. When to use ArrayList vs LinkedList, and the patterns senior developers rely on.
Java Map Interface Explained: HashMap, LinkedHashMap, and TreeMap
Learn the Java Map interface with HashMap, LinkedHashMap, TreeMap, ConcurrentHashMap, key-value lookup, ordering, performance, and real-world examples.