Skip to main content

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.

L1

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: List cannot add(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 Number is an upper bound. T can be Number or a subclass.
  • List is a producer (you can get a Number, you cannot add except null).
  • List is a consumer (you can add an Integer, get returns Object).
Typegetadd
ListIntegerInteger
ListNumberNo (except null)
ListObjectInteger (or subclass)
ListObjectNo (except null)

PECS

  • **Producer Extends, Consumer Super.** copy(List src, List dest).
  • If a method both produces and consumes T, use a plain T (no wildcard).
L2

Advanced — Generics

Type erasure and limitations

  • Generics are erased at runtime: List and List are both List. You cannot write new T() or T[].class cleanly.
  • Overloads cannot differ only by generic type (void f(List) vs void f(List)).
  • Varargs + generics can cause *heap pollution*. Prefer List parameters.
  • Reifiable types (arrays, primitives, List raw) keep their type at runtime; parameterized types do not.
  • Raw types (List without <>) exist for compatibility — never use them in new code.
L3

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>.

L4

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);
    }
}
L5

Problem Solving Tricks

  • If the compiler error mentions “capture#1 of ?”, you probably need a generic helper method .
  • Prefer List.copyOf / Collections.unmodifiableList over exposing a raw mutable list.
  • Do not ignore “raw type” warnings — they disable generic checking.
  • @SafeVarargs is for trusted static/final varargs methods only.
L6

Practice Programs List

  1. Write class Pair with getters and toString.
  2. Write a generic method max for List>.
  3. Demonstrate that List cannot be assigned to List.
  4. Implement copy with PECS and try swapping the wildcards — watch it fail.
  5. Print list.getClass() for List and List — they match.