Advanced Java
Generics
Complete lesson for Generics using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with Java OOP and Collections where relevant.
Basics — Generics
Section: Advanced Java. Type parameters, erasure, bounded types, wildcards, and the PECS rule.
Why generics
- Generics add compile-time type checks to collections and APIs:
Listcannotadd(Integer). - The diamond operator (
new ArrayList<>()) infers the type from the left side (Java 7+). - Type parameters are usually
T,E,K,V. They cannot be primitives — use wrappers.
import java.util.ArrayList;
import java.util.List;
public class Box<T> {
private T value;
void set(T value) {
this.value = value;
}
T get() {
return value;
}
static <E> void swap(List<E> list, int i, int j) {
E tmp = list.get(i);
list.set(i, list.get(j));
list.set(j, tmp);
}
public static void main(String[] args) {
Box<String> b = new Box<>();
b.set("java");
List<String> names = new ArrayList<>();
names.add("a");
names.add("b");
swap(names, 0, 1);
System.out.println(b.get() + " " + names);
}
} Bounds and wildcards
T extends Numberis an upper bound.Tcan beNumberor a subclass.List extends Number>is a producer (you cangetaNumber, you cannotaddexceptnull).List super Integer>is a consumer (you canaddanInteger,getreturnsObject).
| Type | get | add |
|---|---|---|
List | Integer | Integer |
List extends Number> | Number | No (except null) |
List super Integer> | Object | Integer (or subclass) |
List> | Object | No (except null) |
PECS
- **Producer Extends, Consumer Super.**
copy(List extends T> src, List super T> dest). - If a method both produces and consumes
T, use a plainT(no wildcard).
Advanced — Generics
Type erasure and limitations
- Generics are erased at runtime:
ListandListare bothList. You cannot writenew T()orT[].classcleanly. - Overloads cannot differ only by generic type (
void f(Listvs) void f(List).) - Varargs + generics can cause *heap pollution*. Prefer
Listparameters. - Reifiable types (arrays, primitives,
Listraw) keep their type at runtime; parameterized types do not. - Raw types (
Listwithout<>) exist for compatibility — never use them in new code.
Tricky Interview Points
Q1) What is type erasure?
Answer The compiler removes type parameters and inserts casts. At runtime the JVM sees raw types. That is why you cannot new T() or distinguish List<String> from List<Integer> via instanceof.
Q2) Why not List<int>?
Answer Type arguments must be reference types. Use List<Integer> and accept boxing, or a primitive-specialized library.
Q3) What is PECS?
Answer Producer Extends, Consumer Super. Use ? extends T when you only read Ts, ? super T when you only write Ts.
Q4) Diamond operator?
Answer new HashMap<>() infers K,V from the left-hand type. Java 7+.
Q5) Can you overload two methods that differ only in generic parameters?
Answer No. After erasure they have the same signature, so javac rejects them.
Q6) List<?> vs List<Object>?
Answer List<Object> can hold any object and you may add them. List<?> is a list of unknown type; you can only add null. A List<String> is a List<?> but not a List<Object>.
Simple Programs
PECS copy
import java.util.ArrayList;
import java.util.List;
public class PecSCopy {
static <T> void copy(List<? extends T> src, List<? super T> dest) {
for (T item : src) {
dest.add(item);
}
}
public static void main(String[] args) {
List<Integer> src = List.of(1, 2, 3);
List<Number> dest = new ArrayList<>();
copy(src, dest);
System.out.println(dest);
}
} Problem Solving Tricks
- If the compiler error mentions “capture#1 of ?”, you probably need a generic helper method
. - Prefer
List.copyOf/Collections.unmodifiableListover exposing a raw mutable list. - Do not ignore “raw type” warnings — they disable generic checking.
@SafeVarargsis for trusted static/final varargs methods only.