Dr. Vatsal Shah
Subject Material

Java · Collections · Topic 7

Generics

Build type-safe reusable Java classes, methods, and interfaces with bounds, wildcards, inference, and PECS.

Topic progress · 1 of 20 sections

Step 1 of 20

7.1 Introduction to Generics

Learning objective

Explain generic type arguments and compile-time type safety.

A generic type is written inside angle brackets. ArrayList<String> accepts strings, while ArrayList<Integer> accepts integers.

Type-safe lists
ArrayList<String> names = new ArrayList<>();
ArrayList<Integer> numbers = new ArrayList<>();
names.add("Amit");
// names.add(100); // compilation error
Check your understanding: What do angle brackets specify in ArrayList<String>?

The permitted element type, String.

Step 2 of 20

7.2 Need for Generics

Learning objective

Contrast raw collections and runtime casts with generic compile-time checking.

Unsafe raw collection
ArrayList list = new ArrayList();
list.add("Java");
list.add(100);
String value = (String) list.get(1); // ClassCastException
Type-safe replacement
ArrayList<String> list = new ArrayList<>();
list.add("Java");
// list.add(100); // compilation error
Check your understanding: Which exception can an incorrect raw-type cast cause?

ClassCastException.

Step 3 of 20

7.3 Advantages of Generics

Learning objective

Identify the practical benefits of generic code.

Advantages

  • Compile-time type safety
  • Earlier error detection
  • No explicit retrieval casts
  • Reusable classes and methods
  • Clearer declarations
Readable key and value types
Map<Integer, String> students = new HashMap<>();
Check your understanding: Why is String name = names.get(0) possible without casting?

The generic declaration guarantees that list elements are String values.

Step 4 of 20

7.4 Generic Type Parameters

Learning objective

Interpret conventional generic parameter names.

Common type-parameter names
ParameterMeaning
TType
EElement
KKey
VValue
NNumber
RReturn type
Placeholder type
class Box<T> {
    T value;
}
Check your understanding: Which conventional names represent map keys and values?

K and V.

Step 5 of 20

7.5 Generic Class

Learning objective

Define and instantiate a class whose field and methods share one type parameter.

GenericClassDemo.java
class Box<T> {
    private T value;
    void setValue(T value) { this.value = value; }
    T getValue() { return value; }
}

public class GenericClassDemo {
    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<>();
        integerBox.setValue(100);
        System.out.println("Value: " + integerBox.getValue());

        Box<String> stringBox = new Box<>();
        stringBox.setValue("Java");
        System.out.println("Value: " + stringBox.getValue());
    }
}
Output
Value: 100
Value: Java
Check your understanding: Can the same Box class store Integer in one object and String in another?

Yes, each object supplies its own type argument.

Step 6 of 20

7.6 Multiple Type Parameters

Learning objective

Use more than one generic placeholder in a class.

GenericPairDemo.java
class Pair<K, V> {
    private final K key;
    private final V value;
    Pair(K key, V value) { this.key = key; this.value = value; }
    void display() { System.out.println(key + " : " + value); }
}

public class GenericPairDemo {
    public static void main(String[] args) {
        new Pair<>(101, "Amit").display();
        new Pair<>("Laptop", 55000.0).display();
    }
}
Output
101 : Amit
Laptop : 55000.0
Check your understanding: What are the two types in Pair<Integer,String>?

Integer for K and String for V.

Step 7 of 20

7.7 Generic Method

Learning objective

Declare a method with its own type parameter before the return type.

GenericMethodDemo.java
public class GenericMethodDemo {
    static <T> void display(T value) {
        System.out.println(value);
    }
    public static void main(String[] args) {
        display(100); display("Java"); display(45.75); display('A');
    }
}
Output
100
Java
45.75
A
Check your understanding: Where is <T> written in a generic method declaration?

Before the return type.

Step 8 of 20

7.8 Generic Method with an Array

Learning objective

Process object arrays of different element types through one method.

GenericArrayDemo.java
public class GenericArrayDemo {
    static <T> void displayArray(T[] array) {
        for (T element : array) System.out.println(element);
    }
    public static void main(String[] args) {
        displayArray(new Integer[]{10, 20, 30});
        displayArray(new String[]{"Amit", "Neha", "Raj"});
    }
}
Output
10
20
30
Amit
Neha
Raj
Check your understanding: Can displayArray(T[]) accept both Integer[] and String[]?

Yes.

Step 9 of 20

7.9 Generic Interface

Learning objective

Define a type-safe interface and implement it with a fixed or preserved type.

GenericInterfaceDemo.java
interface Container<T> {
    void add(T value);
    T get();
}
class StringContainer implements Container<String> {
    private String value;
    public void add(String value) { this.value = value; }
    public String get() { return value; }
}
public class GenericInterfaceDemo {
    public static void main(String[] args) {
        Container<String> container = new StringContainer();
        container.add("Java Generics");
        System.out.println(container.get());
    }
}
Output
Java Generics
Generic implementation
class MyContainer<T> implements Container<T> {
    private T value;
    public void add(T value) { this.value = value; }
    public T get() { return value; }
}
Check your understanding: What type does StringContainer bind to Container<T>?

String.

Step 10 of 20

7.10 Bounded Type Parameters

Learning objective

Restrict a type parameter to a parent type and its subclasses.

BoundedTypeDemo.java
class Calculator<T extends Number> {
    private final T number;
    Calculator(T number) { this.number = number; }
    double square() { return number.doubleValue() * number.doubleValue(); }
}
public class BoundedTypeDemo {
    public static void main(String[] args) {
        System.out.println(new Calculator<>(5).square());
        System.out.println(new Calculator<>(4.5).square());
    }
}
Output
25.0
20.25

Valid examples

  • Integer
  • Double
  • Float
  • Long
  • Other Number subclasses
Check your understanding: Why is Calculator<String> invalid?

String does not extend Number.

Step 11 of 20

7.11 Multiple Bounds

Learning objective

Combine a class bound with one or more interface bounds.

Multiple-bound syntax
<T extends Number & Comparable<T>>
Check your understanding: Which bound must appear first?

The class bound.

Step 12 of 20

7.12 Wildcards

Learning objective

Explain the unknown-type symbol and the three wildcard forms.

Wildcard forms
FormMeaning
<?>Unknown type
<? extends Type>Type or a subtype
<? super Type>Type or a supertype
Check your understanding: What symbol represents an unknown generic type?

The question mark (?).

Step 13 of 20

7.13 Unbounded Wildcard <?>

Learning objective

Read values from a List of any element type.

WildcardDemo.java
import java.util.Arrays;
import java.util.List;

public class WildcardDemo {
    static void displayList(List<?> list) {
        for (Object element : list) System.out.println(element);
    }
    public static void main(String[] args) {
        displayList(Arrays.asList(10, 20, 30));
        displayList(Arrays.asList("Amit", "Neha"));
    }
}
Output
10
20
30
Amit
Neha
Check your understanding: What common type can safely receive values read from List<?>?

Object.

Step 14 of 20

7.14 Upper-Bounded Wildcard <? extends Type>

Learning objective

Read a family of subtype lists through a common upper bound.

UpperBoundedWildcardDemo.java
import java.util.Arrays;
import java.util.List;

public class UpperBoundedWildcardDemo {
    static double calculateTotal(List<? extends Number> numbers) {
        double total = 0;
        for (Number number : numbers) total += number.doubleValue();
        return total;
    }
    public static void main(String[] args) {
        System.out.println(calculateTotal(Arrays.asList(10, 20, 30)));
    }
}
Output
60.0
Check your understanding: Can List<? extends Number> refer to List<Integer>?

Yes.

Step 15 of 20

7.15 Lower-Bounded Wildcard <? super Type>

Learning objective

Add values through a lower-bounded consumer.

LowerBoundedWildcardDemo.java
import java.util.ArrayList;
import java.util.List;

public class LowerBoundedWildcardDemo {
    static void addNumbers(List<? super Integer> list) {
        list.add(10); list.add(20); list.add(30);
    }
    public static void main(String[] args) {
        List<Number> numbers = new ArrayList<>();
        addNumbers(numbers);
        System.out.println(numbers);
    }
}
Output
[10, 20, 30]
Check your understanding: Which wildcard accepts List<Number> while allowing Integer insertion?

List<? super Integer>.

Step 16 of 20

7.16 Understanding extends and super

Learning objective

Apply the PECS rule to generic API design.

Wildcard purpose
WildcardMain purpose
<?>Work with an unknown type
<? extends Type>Read Type or subtype values
<? super Type>Add Type or subtype values
Check your understanding: What does PECS stand for?

Producer Extends, Consumer Super.

Step 17 of 20

7.17 Type Inference

Learning objective

Use compiler inference for constructors and generic methods.

Diamond operator
ArrayList<String> names = new ArrayList<>();
Generic method inference
display("Java"); // T is String
display(100);    // T is Integer
Check your understanding: What type is inferred on the right side of ArrayList<String> names = new ArrayList<>()?

String.

Step 18 of 20

7.18 Generics and Primitive Types

Learning objective

Use wrapper classes because generic arguments must be reference types.

Primitive wrappers
PrimitiveWrapper
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean
Autoboxing and unboxing
List<Integer> numbers = new ArrayList<>();
numbers.add(10);          // int to Integer
int value = numbers.get(0); // Integer to int
Check your understanding: Which wrapper class represents int?

Integer.

Step 19 of 20

7.19 Raw Types

Learning objective

Recognize and avoid generic types used without a type argument.

Raw and preferred forms
ArrayList list = new ArrayList();              // raw type
ArrayList<String> names = new ArrayList<>();   // preferred

Raw-type risks

  • No compile-time element safety
  • Mixed data types
  • Explicit casts
  • Runtime ClassCastException
Check your understanding: Why should ArrayList list usually be avoided?

It permits mixed types and may require unsafe casts.

Step 20 of 20

7.20 Limitations of Generics

Learning objective

Explain primitive restrictions, type erasure, instantiation limits, generic-array limits, and static context.

Key limitations

  • Primitive type arguments are invalid
  • Most type information is erased at runtime
  • new T() is normally invalid
  • new T[10] is invalid
  • Static members cannot use a class-level type parameter directly
Invalid direct constructions
// T object = new T();
// T[] array = new T[10];
Check your understanding: Can new T() normally create an instance of a type parameter?

No.