Your Box class stores an Object. When you get it out, you cast to String - but what if someone put an Integer in? Generics let you say Box<String> - the compiler ensures only Strings go in, no casting needed.

Generic class

Define a class with a type parameter.

GenericClass.java
Replay: real traced execution (multi-file project)
public class GenericClass {
    static class Box<T> {
        private T value;

        public void set(T value) {
            this.value = value;
        }

        public T get() {
            return value;
        }

        public boolean hasValue() {
            return value != null;
        }
    }

    public static void main(String[] args) {
        System.out.println("Generic class:\n");

        // Box for Integer
        Box<Integer> intBox = new Box<>();
        intBox.set(42);
        System.out.println("  Integer box: " + intBox.get());

        // Box for String
        Box<String> strBox = new Box<>();
        strBox.set("Hello");
        System.out.println("  String box: " + strBox.get());

        // Box for Double
        Box<Double> doubleBox = new Box<>();
        doubleBox.set(3.14);
        System.out.println("  Double box: " + doubleBox.get());

        // T is a type parameter (placeholder for actual type)
        // Specified at instantiation: Box<Integer>
        // Provides compile-time type safety
        // No casting needed when retrieving value

        System.out.println("\nType safety:");

        Box<String> box = new Box<>();
        box.set("Text");
        // box.set(123); // Compile error - type mismatch

        String value = box.get(); // No cast needed
        System.out.println("  Value: " + value);

        System.out.println("\nWithout generics (old way):");

        class ObjectBox {
            private Object value;

            public void set(Object value) {
                this.value = value;
            }

            public Object get() {
                return value;
            }
        }

        ObjectBox oldBox = new ObjectBox();
        oldBox.set("Text");
        String str = (String) oldBox.get(); // Cast required
        System.out.println("  Value: " + str);

        // Runtime error possible:
        oldBox.set(123);
        // String wrong = (String) oldBox.get(); // ClassCastException at runtime

        System.out.println("\nMultiple type uses:");

        Box<Integer> scores = new Box<>();
        scores.set(95);

        Box<String> name = new Box<>();
        name.set("Alice");

        Box<Boolean> active = new Box<>();
        active.set(true);

        System.out.println("  Score: " + scores.get());
        System.out.println("  Name: " + name.get());
        System.out.println("  Active: " + active.get());
    }
}
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Generic class:\n");
    outputGeneric class:
    Generic class:
  2. this.value ← 42

    pass 1 of 7
    5public void set(T value42) {6    this.value→ 42 = value42;7}
    All 7 passes — pass 1 is the card above
    passvaluethis.value
    14242
    2HelloHello
    33.143.14
    4TextText
    59595
    6AliceAlice
    7truetrue
  3. System.out.println(" Integer box: " + intBox.get());

    23intBox.set(42);24System.out.println("  Integer box: " + intBox.get());
  4. public T get()

    pass 1 of 10
    9public T get() {10    return value42;11}
    All 10 passes — pass 1 is the card above
    passvalue
    142
    242
    3Hello
    4Hello
    53.14
    63.14
    7Text
    895
    9Alice
    10true
  5. System.out.println(" Integer box: " + intBox.get());

    23intBox.set(42);24System.out.println("  Integer box: " + intBox.get());
    output  Integer box: 42
  6. System.out.println(" Integer box: " + intBox.get());

    23intBox.set(42);24System.out.println("  Integer box: " + intBox.get());
    output  Integer box: 42
  7. System.out.println(" String box: " + strBox.get());

    28strBox.set("Hello");29System.out.println("  String box: " + strBox.get());
  8. System.out.println(" String box: " + strBox.get());

    28strBox.set("Hello");29System.out.println("  String box: " + strBox.get());
    output  String box: Hello
  9. System.out.println(" String box: " + strBox.get());

    28strBox.set("Hello");29System.out.println("  String box: " + strBox.get());
    output  String box: Hello
  10. System.out.println(" Double box: " + doubleBox.get());

    33doubleBox.set(3.14);34System.out.println("  Double box: " + doubleBox.get());
  11. System.out.println(" Double box: " + doubleBox.get());

    33doubleBox.set(3.14);34System.out.println("  Double box: " + doubleBox.get());
    output  Double box: 3.14
  12. System.out.println(" Double box: " + doubleBox.get());

    33doubleBox.set(3.14);34System.out.println("  Double box: " + doubleBox.get());3536// T is a type parameter (placeholder for actual type)37// Specified at instantiation: Box<Integer>38// Provides compile-time type safety39// No casting needed when retrieving value4041System.out.println("\nType safety:");
    output  Double box: 3.14
    
    Type safety:
    
    Type safety:
  13. System.out.println(" Value: " + value);

    47String value = box.get(); // No cast needed48System.out.println("  Value: " + valueText);4950System.out.println("\nWithout generics (old way):");5152class ObjectBox {53    private Object value;54    55    public void set(Object value) {56        this.value = value;57    }58    59    public Object get() {60        return value;61    }62}6364ObjectBox oldBox = new ObjectBox();65oldBox.set("Text");66String str = (String) oldBox.get(); // Cast required
    output  Value: Text
      Value: Text
    
    Without generics (old way):
    
    Without generics (old way):
  14. this.value ← Text

    pass 1 of 2
    55public void set(Object valueText) {56    this.value→ Text = valueText;57}
  15. oldBox.set("Text");

    64ObjectBox oldBox = new ObjectBox();65oldBox.set("Text");66String str = (String) oldBox.get(); // Cast required67System.out.println("  Value: " + str);
  16. public Object get()

    59public Object get() {60    return valueText;61}
  17. str ← Text

    65oldBox.set("Text");66String str→ Text = (String) oldBox.get(); // Cast required67System.out.println("  Value: " + strText);6869// Runtime error possible:70oldBox.set(123);71// String wrong = (String) oldBox.get(); // ClassCastException at runtime
    output  Value: Text
  18. this.value ← 123

    pass 2 of 2
    55public void set(Object value123) {56    this.value→ 123 = value123;57}
  19. scores ← ⟨GenericClass$Box A⟩

    69// Runtime error possible:70oldBox.set(123);71// String wrong = (String) oldBox.get(); // ClassCastException at runtime7273System.out.println("\nMultiple type uses:");7475Box<Integer> scores→ ⟨GenericClass$Box A⟩ = new Box<>();76scores.set(95);
    output
    Multiple type uses:
  20. name ← ⟨GenericClass$Box B⟩

    75Box<Integer> scores = new Box<>();76scores.set(95);7778Box<String> name→ ⟨GenericClass$Box B⟩ = new Box<>();79name.set("Alice");
  21. active ← ⟨GenericClass$Box C⟩

    78Box<String> name = new Box<>();79name.set("Alice");8081Box<Boolean> active→ ⟨GenericClass$Box C⟩ = new Box<>();82active.set(true);
  22. active.set(true);

    81Box<Boolean> active = new Box<>();82active.set(true);8384System.out.println("  Score: " + scores.get());85System.out.println("  Name: " + name.get());
  23. System.out.println(" Score: " + scores.get());

    84System.out.println("  Score: " + scores.get());85System.out.println("  Name: " + name.get());86System.out.println("  Active: " + active.get());
    output  Score: 95
  24. System.out.println(" Name: " + name.get());

    84    System.out.println("  Score: " + scores.get());85    System.out.println("  Name: " + name.get());86    System.out.println("  Active: " + active.get());87}
    output  Name: Alice
  25. System.out.println(" Active: " + active.get());

    85    System.out.println("  Name: " + name.get());86    System.out.println("  Active: " + active.get());87}
    output  Active: true

class Box<T> - T is a placeholder for any type. Specified when used.

generics Type parameters: `Box<T>`. Compiler enforces type safety. No runtime casts.

Generic with methods

Methods using the type parameter.

pointX
GenericWithMethods.java
Replay: real traced execution (multi-file project)
public class GenericWithMethods {
    static class Container<T> {
        private T item;

        public void store(T item) {
            this.item = item;
            System.out.println("  Stored: " + item);
        }

        public T retrieve() {
            System.out.println("  Retrieved: " + item);
            return item;
        }

        public boolean isEmpty() {
            return item == null;
        }

        public void clear() {
            item = null;
            System.out.println("  Cleared");
        }

        public String getInfo() {
            if (item == null) {
                return "Empty container";
            }
            return "Container holding: " + item.getClass().getSimpleName();
        }
    }

    public static void main(String[] args) {
        System.out.println("Generic methods:\n");

        Container<String> strContainer = new Container<>();
        strContainer.store("Hello");
        String value = strContainer.retrieve();
        System.out.println("  Info: " + strContainer.getInfo());

        // Methods in generic class can use type parameter T
        // Parameters and return types can be T
        // Type is consistent throughout the instance

        System.out.println("\nInteger container:");

        Container<Integer> intContainer = new Container<>();
        System.out.println("  Empty: " + intContainer.isEmpty());
        intContainer.store(42);
        System.out.println("  Empty: " + intContainer.isEmpty());
        int num = intContainer.retrieve();
        System.out.println("  Value: " + num);

        System.out.println("\nPair class:");

        class Pair<T> {
            private T first;
            private T second;

            public Pair(T first, T second) {
                this.first = first;
                this.second = second;
            }

            public T getFirst() {
                return first;
            }

            public T getSecond() {
                return second;
            }

            public void swap() {
                T temp = first;
                first = second;
                second = temp;
            }

            public void display() {
                System.out.println("  First: " + first + ", Second: " + second);
            }
        }

        Pair<String> namePair = new Pair<>("Alice", "Bob");
        namePair.display();
        namePair.swap();
        System.out.println("  After swap:");
        namePair.display();

        System.out.println("\nPoint class:");

        class Point<T extends Number> {
            private T x;
            private T y;

            public Point(T x, T y) {
                this.x = x;
                this.y = y;
            }

            public T getX() { return x; }
            public T getY() { return y; }

            public double distance() {
                double dx = x.doubleValue();
                double dy = y.doubleValue();
                return Math.sqrt(dx * dx + dy * dy);
            }

            public void display() {
                System.out.println("  Point(" + x + ", " + y + ")");
            }
        }

        int pointX = 3;
        Point<Integer> intPoint = new Point<>(pointX, 4);
        intPoint.display();
        System.out.println("  Distance: " + intPoint.distance());

        Point<Double> doublePoint = new Point<>(1.5, 2.5);
        doublePoint.display();
        System.out.println("  Distance: " + doublePoint.distance());
    }
}
public class GenericWithMethods {
    static class Container<T> {
        private T item;

        public void store(T item) {
            this.item = item;
            System.out.println("  Stored: " + item);
        }

        public T retrieve() {
            System.out.println("  Retrieved: " + item);
            return item;
        }

        public boolean isEmpty() {
            return item == null;
        }

        public void clear() {
            item = null;
            System.out.println("  Cleared");
        }

        public String getInfo() {
            if (item == null) {
                return "Empty container";
            }
            return "Container holding: " + item.getClass().getSimpleName();
        }
    }

    public static void main(String[] args) {
        System.out.println("Generic methods:\n");

        Container<String> strContainer = new Container<>();
        strContainer.store("Hello");
        String value = strContainer.retrieve();
        System.out.println("  Info: " + strContainer.getInfo());

        // Methods in generic class can use type parameter T
        // Parameters and return types can be T
        // Type is consistent throughout the instance

        System.out.println("\nInteger container:");

        Container<Integer> intContainer = new Container<>();
        System.out.println("  Empty: " + intContainer.isEmpty());
        intContainer.store(42);
        System.out.println("  Empty: " + intContainer.isEmpty());
        int num = intContainer.retrieve();
        System.out.println("  Value: " + num);

        System.out.println("\nPair class:");

        class Pair<T> {
            private T first;
            private T second;

            public Pair(T first, T second) {
                this.first = first;
                this.second = second;
            }

            public T getFirst() {
                return first;
            }

            public T getSecond() {
                return second;
            }

            public void swap() {
                T temp = first;
                first = second;
                second = temp;
            }

            public void display() {
                System.out.println("  First: " + first + ", Second: " + second);
            }
        }

        Pair<String> namePair = new Pair<>("Alice", "Bob");
        namePair.display();
        namePair.swap();
        System.out.println("  After swap:");
        namePair.display();

        System.out.println("\nPoint class:");

        class Point<T extends Number> {
            private T x;
            private T y;

            public Point(T x, T y) {
                this.x = x;
                this.y = y;
            }

            public T getX() { return x; }
            public T getY() { return y; }

            public double distance() {
                double dx = x.doubleValue();
                double dy = y.doubleValue();
                return Math.sqrt(dx * dx + dy * dy);
            }

            public void display() {
                System.out.println("  Point(" + x + ", " + y + ")");
            }
        }

        int pointX = 5;
        Point<Integer> intPoint = new Point<>(pointX, 4);
        intPoint.display();
        System.out.println("  Distance: " + intPoint.distance());

        Point<Double> doublePoint = new Point<>(1.5, 2.5);
        doublePoint.display();
        System.out.println("  Distance: " + doublePoint.distance());
    }
}
public class GenericWithMethods {
    static class Container<T> {
        private T item;

        public void store(T item) {
            this.item = item;
            System.out.println("  Stored: " + item);
        }

        public T retrieve() {
            System.out.println("  Retrieved: " + item);
            return item;
        }

        public boolean isEmpty() {
            return item == null;
        }

        public void clear() {
            item = null;
            System.out.println("  Cleared");
        }

        public String getInfo() {
            if (item == null) {
                return "Empty container";
            }
            return "Container holding: " + item.getClass().getSimpleName();
        }
    }

    public static void main(String[] args) {
        System.out.println("Generic methods:\n");

        Container<String> strContainer = new Container<>();
        strContainer.store("Hello");
        String value = strContainer.retrieve();
        System.out.println("  Info: " + strContainer.getInfo());

        // Methods in generic class can use type parameter T
        // Parameters and return types can be T
        // Type is consistent throughout the instance

        System.out.println("\nInteger container:");

        Container<Integer> intContainer = new Container<>();
        System.out.println("  Empty: " + intContainer.isEmpty());
        intContainer.store(42);
        System.out.println("  Empty: " + intContainer.isEmpty());
        int num = intContainer.retrieve();
        System.out.println("  Value: " + num);

        System.out.println("\nPair class:");

        class Pair<T> {
            private T first;
            private T second;

            public Pair(T first, T second) {
                this.first = first;
                this.second = second;
            }

            public T getFirst() {
                return first;
            }

            public T getSecond() {
                return second;
            }

            public void swap() {
                T temp = first;
                first = second;
                second = temp;
            }

            public void display() {
                System.out.println("  First: " + first + ", Second: " + second);
            }
        }

        Pair<String> namePair = new Pair<>("Alice", "Bob");
        namePair.display();
        namePair.swap();
        System.out.println("  After swap:");
        namePair.display();

        System.out.println("\nPoint class:");

        class Point<T extends Number> {
            private T x;
            private T y;

            public Point(T x, T y) {
                this.x = x;
                this.y = y;
            }

            public T getX() { return x; }
            public T getY() { return y; }

            public double distance() {
                double dx = x.doubleValue();
                double dy = y.doubleValue();
                return Math.sqrt(dx * dx + dy * dy);
            }

            public void display() {
                System.out.println("  Point(" + x + ", " + y + ")");
            }
        }

        int pointX = 6;
        Point<Integer> intPoint = new Point<>(pointX, 4);
        intPoint.display();
        System.out.println("  Distance: " + intPoint.distance());

        Point<Double> doublePoint = new Point<>(1.5, 2.5);
        doublePoint.display();
        System.out.println("  Distance: " + doublePoint.distance());
    }
}
  1. public static void main(String[] args)

    32public static void main(String[] args) {33    System.out.println("Generic methods:\n");
    outputGeneric methods:
    Generic methods:
  2. this.item ← Hello

    pass 1 of 2
    5public void store(T itemHello) {6    this.item→ Hello = itemHello;7    System.out.println("  Stored: " + itemHello);8}
    output  Stored: Hello
  3. public T retrieve()

    pass 1 of 2
    10public T retrieve() {11    System.out.println("  Retrieved: " + itemHello);12    return itemHello;13}
    output  Retrieved: Hello
  4. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());
  5. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());
    output  Info: Container holding: String
  6. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());3940// Methods in generic class can use type parameter T41// Parameters and return types can be T42// Type is consistent throughout the instance4344System.out.println("\nInteger container:");4546Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Info: Container holding: String
    
    Integer container:
    
    Integer container:
  7. public boolean isEmpty()

    pass 1 of 4
    15public boolean isEmpty() {16    return itemnull == null;17}
    All 4 passes — pass 1 is the card above
    passitem
    1null
    2null
    342
    442
  8. System.out.println(" Empty: " + intContainer.isEmpty());

    46Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Empty: true
  9. System.out.println(" Empty: " + intContainer.isEmpty());

    46Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Empty: true
  10. this.item ← 42

    pass 2 of 2
    5public void store(T item42) {6    this.item→ 42 = item42;7    System.out.println("  Stored: " + item42);8}
    output  Stored: 42
  11. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
  12. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
    output  Empty: false
  13. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
    output  Empty: false
  14. public T retrieve()

    pass 2 of 2
    10public T retrieve() {11    System.out.println("  Retrieved: " + item42);12    return item42;13}
    output  Retrieved: 42
  15. System.out.println(" Value: " + num);

    50int num = intContainer.retrieve();51System.out.println("  Value: " + num42);5253System.out.println("\nPair class:");
    output  Value: 42
      Value: 42
    
    Pair class:
    
    Pair class:
  16. this.first ← Alice, this.second ← Bob

    59public Pair(T firstAlice, T secondBob) {60    this.first→ Alice = firstAlice;61    this.second→ Bob = secondBob;62}
  17. public void display()

    pass 1 of 2
    78public void display() {79    System.out.println("  First: " + firstAlice + ", Second: " + secondBob);80}
    output  First: Alice, Second: Bob
  18. temp ← Alice, first ← Bob, second ← Alice

    72public void swap() {73    T temp→ Alice = first;74    first→ Bob = secondBob;75    second→ Alice = tempAlice;76}
  19. System.out.println(" After swap:");

    85namePair.swap();86System.out.println("  After swap:");87namePair.display();
    output  After swap:
      After swap:
  20. public void display()

    pass 2 of 2
    78public void display() {79    System.out.println("  First: " + firstBob + ", Second: " + secondAlice);80}
    output  First: Bob, Second: Alice
  21. System.out.println(" Point class:");

    89System.out.println("\nPoint class:");9091class Point<T extends Number> {92    private T x;93    private T y;94    95    public Point(T x, T y) {96        this.x = x;97        this.y = y;98    }99    100    public T getX() { return x; }101    public T getY() { return y; }102    103    public double distance() {104        double dx = x.doubleValue();105        double dy = y.doubleValue();106        return Math.sqrt(dx * dx + dy * dy);107    }108    109    public void display() {110        System.out.println("  Point(" + x + ", " + y + ")");111    }112}113114int pointX = 3; //@pointX=3, 5, 6115Point<Integer> intPoint = new Point<>(pointX, 4);116intPoint.display();
    output
    Point class:
    
    Point class:
  22. this.x ← 3, this.y ← 4

    pass 1 of 2
    95public Point(T x3, T y4) {96    this.x→ 3 = x3;97    this.y→ 4 = y4;98}
  23. intPoint ← ⟨GenericWithMethods$1Point A⟩

    114int pointX = 3; //@pointX=3, 5, 6115Point<Integer> intPoint→ ⟨GenericWithMethods$1Point A⟩ = new Point<>(pointX, 4);116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());
  24. public void display()

    pass 1 of 2
    109public void display() {110    System.out.println("  Point(" + x3 + ", " + y4 + ")");111}
    output  Point(3, 4)
  25. intPoint.display();

    115Point<Integer> intPoint = new Point<>(pointX, 4);116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());
  26. dx ← 3.0, dy ← 4.0

    pass 1 of 2
    103public double distance() {104    double dx→ 3.0 = x.doubleValue();105    double dy→ 4.0 = y.doubleValue();106    return Math.sqrt(dx3.0 * dx + dy4.0 * dy);107}
  27. System.out.println(" Distance: " + intPoint.distance());

    116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());118119Point<Double> doublePoint = new Point<>(1.5, 2.5);120doublePoint.display();
    output  Distance: 5.0
  28. this.x ← 1.5, this.y ← 2.5

    pass 2 of 2
    95public Point(T x1.5, T y2.5) {96    this.x→ 1.5 = x1.5;97    this.y→ 2.5 = y2.5;98}
  29. doublePoint ← ⟨GenericWithMethods$1Point B⟩

    119Point<Double> doublePoint→ ⟨GenericWithMethods$1Point B⟩ = new Point<>(1.5, 2.5);120doublePoint.display();121System.out.println("  Distance: " + doublePoint.distance());
  30. public void display()

    pass 2 of 2
    109public void display() {110    System.out.println("  Point(" + x1.5 + ", " + y2.5 + ")");111}
    output  Point(1.5, 2.5)
  31. doublePoint.display();

    119    Point<Double> doublePoint = new Point<>(1.5, 2.5);120    doublePoint.display();121    System.out.println("  Distance: " + doublePoint.distance());122}
  32. dx ← 1.5, dy ← 2.5

    pass 2 of 2
    103public double distance() {104    double dx→ 1.5 = x.doubleValue();105    double dy→ 2.5 = y.doubleValue();106    return Math.sqrt(dx1.5 * dx + dy2.5 * dy);107}
  33. System.out.println(" Distance: " + doublePoint.distance());

    120    doublePoint.display();121    System.out.println("  Distance: " + doublePoint.distance());122}
    output  Distance: 2.9154759474226504
  1. public static void main(String[] args)

    32public static void main(String[] args) {33    System.out.println("Generic methods:\n");
    outputGeneric methods:
    Generic methods:
  2. this.item ← Hello

    pass 1 of 2
    5public void store(T itemHello) {6    this.item→ Hello = itemHello;7    System.out.println("  Stored: " + itemHello);8}
    output  Stored: Hello
  3. public T retrieve()

    pass 1 of 2
    10public T retrieve() {11    System.out.println("  Retrieved: " + itemHello);12    return itemHello;13}
    output  Retrieved: Hello
  4. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());
  5. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());
    output  Info: Container holding: String
  6. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());3940// Methods in generic class can use type parameter T41// Parameters and return types can be T42// Type is consistent throughout the instance4344System.out.println("\nInteger container:");4546Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Info: Container holding: String
    
    Integer container:
    
    Integer container:
  7. public boolean isEmpty()

    pass 1 of 4
    15public boolean isEmpty() {16    return itemnull == null;17}
    All 4 passes — pass 1 is the card above
    passitem
    1null
    2null
    342
    442
  8. System.out.println(" Empty: " + intContainer.isEmpty());

    46Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Empty: true
  9. System.out.println(" Empty: " + intContainer.isEmpty());

    46Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Empty: true
  10. this.item ← 42

    pass 2 of 2
    5public void store(T item42) {6    this.item→ 42 = item42;7    System.out.println("  Stored: " + item42);8}
    output  Stored: 42
  11. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
  12. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
    output  Empty: false
  13. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
    output  Empty: false
  14. public T retrieve()

    pass 2 of 2
    10public T retrieve() {11    System.out.println("  Retrieved: " + item42);12    return item42;13}
    output  Retrieved: 42
  15. System.out.println(" Value: " + num);

    50int num = intContainer.retrieve();51System.out.println("  Value: " + num42);5253System.out.println("\nPair class:");
    output  Value: 42
      Value: 42
    
    Pair class:
    
    Pair class:
  16. this.first ← Alice, this.second ← Bob

    59public Pair(T firstAlice, T secondBob) {60    this.first→ Alice = firstAlice;61    this.second→ Bob = secondBob;62}
  17. public void display()

    pass 1 of 2
    78public void display() {79    System.out.println("  First: " + firstAlice + ", Second: " + secondBob);80}
    output  First: Alice, Second: Bob
  18. temp ← Alice, first ← Bob, second ← Alice

    72public void swap() {73    T temp→ Alice = first;74    first→ Bob = secondBob;75    second→ Alice = tempAlice;76}
  19. System.out.println(" After swap:");

    85namePair.swap();86System.out.println("  After swap:");87namePair.display();
    output  After swap:
      After swap:
  20. public void display()

    pass 2 of 2
    78public void display() {79    System.out.println("  First: " + firstBob + ", Second: " + secondAlice);80}
    output  First: Bob, Second: Alice
  21. System.out.println(" Point class:");

    89System.out.println("\nPoint class:");9091class Point<T extends Number> {92    private T x;93    private T y;94    95    public Point(T x, T y) {96        this.x = x;97        this.y = y;98    }99    100    public T getX() { return x; }101    public T getY() { return y; }102    103    public double distance() {104        double dx = x.doubleValue();105        double dy = y.doubleValue();106        return Math.sqrt(dx * dx + dy * dy);107    }108    109    public void display() {110        System.out.println("  Point(" + x + ", " + y + ")");111    }112}113114int pointX = 5;115Point<Integer> intPoint = new Point<>(pointX, 4);116intPoint.display();
    output
    Point class:
    
    Point class:
  22. this.x ← 5, this.y ← 4

    pass 1 of 2
    95public Point(T x5, T y4) {96    this.x→ 5 = x5;97    this.y→ 4 = y4;98}
  23. intPoint ← ⟨GenericWithMethods$1Point A⟩

    114int pointX = 5;115Point<Integer> intPoint→ ⟨GenericWithMethods$1Point A⟩ = new Point<>(pointX, 4);116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());
  24. public void display()

    pass 1 of 2
    109public void display() {110    System.out.println("  Point(" + x5 + ", " + y4 + ")");111}
    output  Point(5, 4)
  25. intPoint.display();

    115Point<Integer> intPoint = new Point<>(pointX, 4);116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());
  26. dx ← 5.0, dy ← 4.0

    pass 1 of 2
    103public double distance() {104    double dx→ 5.0 = x.doubleValue();105    double dy→ 4.0 = y.doubleValue();106    return Math.sqrt(dx5.0 * dx + dy4.0 * dy);107}
  27. System.out.println(" Distance: " + intPoint.distance());

    116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());118119Point<Double> doublePoint = new Point<>(1.5, 2.5);120doublePoint.display();
    output  Distance: 6.4031242374328485
  28. this.x ← 1.5, this.y ← 2.5

    pass 2 of 2
    95public Point(T x1.5, T y2.5) {96    this.x→ 1.5 = x1.5;97    this.y→ 2.5 = y2.5;98}
  29. doublePoint ← ⟨GenericWithMethods$1Point B⟩

    119Point<Double> doublePoint→ ⟨GenericWithMethods$1Point B⟩ = new Point<>(1.5, 2.5);120doublePoint.display();121System.out.println("  Distance: " + doublePoint.distance());
  30. public void display()

    pass 2 of 2
    109public void display() {110    System.out.println("  Point(" + x1.5 + ", " + y2.5 + ")");111}
    output  Point(1.5, 2.5)
  31. doublePoint.display();

    119    Point<Double> doublePoint = new Point<>(1.5, 2.5);120    doublePoint.display();121    System.out.println("  Distance: " + doublePoint.distance());122}
  32. dx ← 1.5, dy ← 2.5

    pass 2 of 2
    103public double distance() {104    double dx→ 1.5 = x.doubleValue();105    double dy→ 2.5 = y.doubleValue();106    return Math.sqrt(dx1.5 * dx + dy2.5 * dy);107}
  33. System.out.println(" Distance: " + doublePoint.distance());

    120    doublePoint.display();121    System.out.println("  Distance: " + doublePoint.distance());122}
    output  Distance: 2.9154759474226504
  1. public static void main(String[] args)

    32public static void main(String[] args) {33    System.out.println("Generic methods:\n");
    outputGeneric methods:
    Generic methods:
  2. this.item ← Hello

    pass 1 of 2
    5public void store(T itemHello) {6    this.item→ Hello = itemHello;7    System.out.println("  Stored: " + itemHello);8}
    output  Stored: Hello
  3. public T retrieve()

    pass 1 of 2
    10public T retrieve() {11    System.out.println("  Retrieved: " + itemHello);12    return itemHello;13}
    output  Retrieved: Hello
  4. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());
  5. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());
    output  Info: Container holding: String
  6. System.out.println(" Info: " + strContainer.getInfo());

    37String value = strContainer.retrieve();38System.out.println("  Info: " + strContainer.getInfo());3940// Methods in generic class can use type parameter T41// Parameters and return types can be T42// Type is consistent throughout the instance4344System.out.println("\nInteger container:");4546Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Info: Container holding: String
    
    Integer container:
    
    Integer container:
  7. public boolean isEmpty()

    pass 1 of 4
    15public boolean isEmpty() {16    return itemnull == null;17}
    All 4 passes — pass 1 is the card above
    passitem
    1null
    2null
    342
    442
  8. System.out.println(" Empty: " + intContainer.isEmpty());

    46Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Empty: true
  9. System.out.println(" Empty: " + intContainer.isEmpty());

    46Container<Integer> intContainer = new Container<>();47System.out.println("  Empty: " + intContainer.isEmpty());48intContainer.store(42);
    output  Empty: true
  10. this.item ← 42

    pass 2 of 2
    5public void store(T item42) {6    this.item→ 42 = item42;7    System.out.println("  Stored: " + item42);8}
    output  Stored: 42
  11. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
  12. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
    output  Empty: false
  13. System.out.println(" Empty: " + intContainer.isEmpty());

    48intContainer.store(42);49System.out.println("  Empty: " + intContainer.isEmpty());50int num = intContainer.retrieve();
    output  Empty: false
  14. public T retrieve()

    pass 2 of 2
    10public T retrieve() {11    System.out.println("  Retrieved: " + item42);12    return item42;13}
    output  Retrieved: 42
  15. System.out.println(" Value: " + num);

    50int num = intContainer.retrieve();51System.out.println("  Value: " + num42);5253System.out.println("\nPair class:");
    output  Value: 42
      Value: 42
    
    Pair class:
    
    Pair class:
  16. this.first ← Alice, this.second ← Bob

    59public Pair(T firstAlice, T secondBob) {60    this.first→ Alice = firstAlice;61    this.second→ Bob = secondBob;62}
  17. public void display()

    pass 1 of 2
    78public void display() {79    System.out.println("  First: " + firstAlice + ", Second: " + secondBob);80}
    output  First: Alice, Second: Bob
  18. temp ← Alice, first ← Bob, second ← Alice

    72public void swap() {73    T temp→ Alice = first;74    first→ Bob = secondBob;75    second→ Alice = tempAlice;76}
  19. System.out.println(" After swap:");

    85namePair.swap();86System.out.println("  After swap:");87namePair.display();
    output  After swap:
      After swap:
  20. public void display()

    pass 2 of 2
    78public void display() {79    System.out.println("  First: " + firstBob + ", Second: " + secondAlice);80}
    output  First: Bob, Second: Alice
  21. System.out.println(" Point class:");

    89System.out.println("\nPoint class:");9091class Point<T extends Number> {92    private T x;93    private T y;94    95    public Point(T x, T y) {96        this.x = x;97        this.y = y;98    }99    100    public T getX() { return x; }101    public T getY() { return y; }102    103    public double distance() {104        double dx = x.doubleValue();105        double dy = y.doubleValue();106        return Math.sqrt(dx * dx + dy * dy);107    }108    109    public void display() {110        System.out.println("  Point(" + x + ", " + y + ")");111    }112}113114int pointX = 6;115Point<Integer> intPoint = new Point<>(pointX, 4);116intPoint.display();
    output
    Point class:
    
    Point class:
  22. this.x ← 6, this.y ← 4

    pass 1 of 2
    95public Point(T x6, T y4) {96    this.x→ 6 = x6;97    this.y→ 4 = y4;98}
  23. intPoint ← ⟨GenericWithMethods$1Point A⟩

    114int pointX = 6;115Point<Integer> intPoint→ ⟨GenericWithMethods$1Point A⟩ = new Point<>(pointX, 4);116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());
  24. public void display()

    pass 1 of 2
    109public void display() {110    System.out.println("  Point(" + x6 + ", " + y4 + ")");111}
    output  Point(6, 4)
  25. intPoint.display();

    115Point<Integer> intPoint = new Point<>(pointX, 4);116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());
  26. dx ← 6.0, dy ← 4.0

    pass 1 of 2
    103public double distance() {104    double dx→ 6.0 = x.doubleValue();105    double dy→ 4.0 = y.doubleValue();106    return Math.sqrt(dx6.0 * dx + dy4.0 * dy);107}
  27. System.out.println(" Distance: " + intPoint.distance());

    116intPoint.display();117System.out.println("  Distance: " + intPoint.distance());118119Point<Double> doublePoint = new Point<>(1.5, 2.5);120doublePoint.display();
    output  Distance: 7.211102550927978
  28. this.x ← 1.5, this.y ← 2.5

    pass 2 of 2
    95public Point(T x1.5, T y2.5) {96    this.x→ 1.5 = x1.5;97    this.y→ 2.5 = y2.5;98}
  29. doublePoint ← ⟨GenericWithMethods$1Point B⟩

    119Point<Double> doublePoint→ ⟨GenericWithMethods$1Point B⟩ = new Point<>(1.5, 2.5);120doublePoint.display();121System.out.println("  Distance: " + doublePoint.distance());
  30. public void display()

    pass 2 of 2
    109public void display() {110    System.out.println("  Point(" + x1.5 + ", " + y2.5 + ")");111}
    output  Point(1.5, 2.5)
  31. doublePoint.display();

    119    Point<Double> doublePoint = new Point<>(1.5, 2.5);120    doublePoint.display();121    System.out.println("  Distance: " + doublePoint.distance());122}
  32. dx ← 1.5, dy ← 2.5

    pass 2 of 2
    103public double distance() {104    double dx→ 1.5 = x.doubleValue();105    double dy→ 2.5 = y.doubleValue();106    return Math.sqrt(dx1.5 * dx + dy2.5 * dy);107}
  33. System.out.println(" Distance: " + doublePoint.distance());

    120    doublePoint.display();121    System.out.println("  Distance: " + doublePoint.distance());122}
    output  Distance: 2.9154759474226504

Type parameter T available in fields, methods, and return types.

Multiple type parameters

Use more than one type parameter.

lookupName
MultipleTypeParams.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class MultipleTypeParams {
    static class Pair<K, V> {
        private K key;
        private V value;

        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        public void display() {
            System.out.println("  " + key + " -> " + value);
        }
    }

    public static void main(String[] args) {
        System.out.println("Multiple type parameters:\n");

        Pair<String, Integer> agePair = new Pair<>("Alice", 30);
        agePair.display();

        Pair<Integer, String> namePair = new Pair<>(1, "Bob");
        namePair.display();

        Pair<String, Double> pricePair = new Pair<>("Coffee", 3.50);
        pricePair.display();

        // Multiple type parameters separated by commas: <K, V>
        // Each can be a different type
        // Common in key-value data structures

        System.out.println("\nSimple map:");

        class SimpleMap<K, V> {
            private List<K> keys = new ArrayList<>();
            private List<V> values = new ArrayList<>();

            public void put(K key, V value) {
                keys.add(key);
                values.add(value);
            }

            public V get(K key) {
                int index = keys.indexOf(key);
                return index >= 0 ? values.get(index) : null;
            }

            public void display() {
                for (int i = 0; i < keys.size(); i++) {
                    System.out.println("  " + keys.get(i) + " = " + values.get(i));
                }
            }
        }

        SimpleMap<String, Integer> scores = new SimpleMap<>();
        scores.put("Alice", 95);
        scores.put("Bob", 87);
        scores.put("Charlie", 92);
        scores.display();

        String lookupName = "Alice";
        System.out.println("  " + lookupName + "'s score: " + scores.get(lookupName));

        System.out.println("\nTriple class:");

        class Triple<A, B, C> {
            private A first;
            private B second;
            private C third;

            public Triple(A first, B second, C third) {
                this.first = first;
                this.second = second;
                this.third = third;
            }

            public A getFirst() { return first; }
            public B getSecond() { return second; }
            public C getThird() { return third; }

            public void display() {
                System.out.println("  (" + first + ", " + second + ", " + third + ")");
            }
        }

        Triple<String, Integer, Double> studentRecord =
            new Triple<>("Alice", 20, 3.8);
        studentRecord.display();

        Triple<Integer, String, Boolean> config =
            new Triple<>(8080, "localhost", true);
        config.display();

        System.out.println("\nEntry class:");

        class Entry<K, V> {
            private K key;
            private V value;
            private long timestamp;

            public Entry(K key, V value) {
                this.key = key;
                this.value = value;
                this.timestamp = 1000L;
            }

            public K getKey() { return key; }
            public V getValue() { return value; }

            public void setValue(V value) {
                this.value = value;
                this.timestamp = 1001L;
            }

            public void display() {
                System.out.println("  " + key + ": " + value +
                                   " (ts: " + timestamp + ")");
            }
        }

        Entry<String, String> config1 = new Entry<>("host", "localhost");
        config1.display();

        Entry<Integer, List<String>> userTags =
            new Entry<>(101, Arrays.asList("admin", "active"));
        userTags.display();
    }
}
import java.util.*;

public class MultipleTypeParams {
    static class Pair<K, V> {
        private K key;
        private V value;

        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        public void display() {
            System.out.println("  " + key + " -> " + value);
        }
    }

    public static void main(String[] args) {
        System.out.println("Multiple type parameters:\n");

        Pair<String, Integer> agePair = new Pair<>("Alice", 30);
        agePair.display();

        Pair<Integer, String> namePair = new Pair<>(1, "Bob");
        namePair.display();

        Pair<String, Double> pricePair = new Pair<>("Coffee", 3.50);
        pricePair.display();

        // Multiple type parameters separated by commas: <K, V>
        // Each can be a different type
        // Common in key-value data structures

        System.out.println("\nSimple map:");

        class SimpleMap<K, V> {
            private List<K> keys = new ArrayList<>();
            private List<V> values = new ArrayList<>();

            public void put(K key, V value) {
                keys.add(key);
                values.add(value);
            }

            public V get(K key) {
                int index = keys.indexOf(key);
                return index >= 0 ? values.get(index) : null;
            }

            public void display() {
                for (int i = 0; i < keys.size(); i++) {
                    System.out.println("  " + keys.get(i) + " = " + values.get(i));
                }
            }
        }

        SimpleMap<String, Integer> scores = new SimpleMap<>();
        scores.put("Alice", 95);
        scores.put("Bob", 87);
        scores.put("Charlie", 92);
        scores.display();

        String lookupName = "Bob";
        System.out.println("  " + lookupName + "'s score: " + scores.get(lookupName));

        System.out.println("\nTriple class:");

        class Triple<A, B, C> {
            private A first;
            private B second;
            private C third;

            public Triple(A first, B second, C third) {
                this.first = first;
                this.second = second;
                this.third = third;
            }

            public A getFirst() { return first; }
            public B getSecond() { return second; }
            public C getThird() { return third; }

            public void display() {
                System.out.println("  (" + first + ", " + second + ", " + third + ")");
            }
        }

        Triple<String, Integer, Double> studentRecord =
            new Triple<>("Alice", 20, 3.8);
        studentRecord.display();

        Triple<Integer, String, Boolean> config =
            new Triple<>(8080, "localhost", true);
        config.display();

        System.out.println("\nEntry class:");

        class Entry<K, V> {
            private K key;
            private V value;
            private long timestamp;

            public Entry(K key, V value) {
                this.key = key;
                this.value = value;
                this.timestamp = 1000L;
            }

            public K getKey() { return key; }
            public V getValue() { return value; }

            public void setValue(V value) {
                this.value = value;
                this.timestamp = 1001L;
            }

            public void display() {
                System.out.println("  " + key + ": " + value +
                                   " (ts: " + timestamp + ")");
            }
        }

        Entry<String, String> config1 = new Entry<>("host", "localhost");
        config1.display();

        Entry<Integer, List<String>> userTags =
            new Entry<>(101, Arrays.asList("admin", "active"));
        userTags.display();
    }
}
import java.util.*;

public class MultipleTypeParams {
    static class Pair<K, V> {
        private K key;
        private V value;

        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }

        public void display() {
            System.out.println("  " + key + " -> " + value);
        }
    }

    public static void main(String[] args) {
        System.out.println("Multiple type parameters:\n");

        Pair<String, Integer> agePair = new Pair<>("Alice", 30);
        agePair.display();

        Pair<Integer, String> namePair = new Pair<>(1, "Bob");
        namePair.display();

        Pair<String, Double> pricePair = new Pair<>("Coffee", 3.50);
        pricePair.display();

        // Multiple type parameters separated by commas: <K, V>
        // Each can be a different type
        // Common in key-value data structures

        System.out.println("\nSimple map:");

        class SimpleMap<K, V> {
            private List<K> keys = new ArrayList<>();
            private List<V> values = new ArrayList<>();

            public void put(K key, V value) {
                keys.add(key);
                values.add(value);
            }

            public V get(K key) {
                int index = keys.indexOf(key);
                return index >= 0 ? values.get(index) : null;
            }

            public void display() {
                for (int i = 0; i < keys.size(); i++) {
                    System.out.println("  " + keys.get(i) + " = " + values.get(i));
                }
            }
        }

        SimpleMap<String, Integer> scores = new SimpleMap<>();
        scores.put("Alice", 95);
        scores.put("Bob", 87);
        scores.put("Charlie", 92);
        scores.display();

        String lookupName = "Charlie";
        System.out.println("  " + lookupName + "'s score: " + scores.get(lookupName));

        System.out.println("\nTriple class:");

        class Triple<A, B, C> {
            private A first;
            private B second;
            private C third;

            public Triple(A first, B second, C third) {
                this.first = first;
                this.second = second;
                this.third = third;
            }

            public A getFirst() { return first; }
            public B getSecond() { return second; }
            public C getThird() { return third; }

            public void display() {
                System.out.println("  (" + first + ", " + second + ", " + third + ")");
            }
        }

        Triple<String, Integer, Double> studentRecord =
            new Triple<>("Alice", 20, 3.8);
        studentRecord.display();

        Triple<Integer, String, Boolean> config =
            new Triple<>(8080, "localhost", true);
        config.display();

        System.out.println("\nEntry class:");

        class Entry<K, V> {
            private K key;
            private V value;
            private long timestamp;

            public Entry(K key, V value) {
                this.key = key;
                this.value = value;
                this.timestamp = 1000L;
            }

            public K getKey() { return key; }
            public V getValue() { return value; }

            public void setValue(V value) {
                this.value = value;
                this.timestamp = 1001L;
            }

            public void display() {
                System.out.println("  " + key + ": " + value +
                                   " (ts: " + timestamp + ")");
            }
        }

        Entry<String, String> config1 = new Entry<>("host", "localhost");
        config1.display();

        Entry<Integer, List<String>> userTags =
            new Entry<>(101, Arrays.asList("admin", "active"));
        userTags.display();
    }
}
  1. public static void main(String[] args)

    26public static void main(String[] args) {27    System.out.println("Multiple type parameters:\n");
    outputMultiple type parameters:
    Multiple type parameters:
  2. this.key ← Alice, this.value ← 30

    pass 1 of 3
    8public Pair(K keyAlice, V value30) {9    this.key→ Alice = keyAlice;10    this.value→ 30 = value30;11}
    All 3 passes — pass 1 is the card above
    passkeyvaluethis.keythis.value
    1Alice30Alice30
    21Bob1Bob
    3Coffee3.5Coffee3.5
  3. public void display()

    pass 1 of 3
    21public void display() {22    System.out.println("  " + keyAlice + " -> " + value30);23}
    output  Alice -> 30
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1Alice30
    21Bob
    3Coffee3.5
  4. System.out.println(" Simple map:");

    42System.out.println("\nSimple map:");
    output
    Simple map:
    
    Simple map:
  5. public void put(K key, V value)

    pass 1 of 3
    48public void put(K keyAlice, V value95) {49    keys.add(keyAlice);50    values.add(value95);51}
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1Alice95
    2Bob87
    3Charlie92
  6. for (int i = 0; i < keys.size(); i++)

    pass 1 of 3
    58public void display() {59    for (int i0 = 0; i < keys.size(); i++) {60        System.out.println("  " + keys.get(i0) + " = " + values.get(i));61    }
    output  Alice = 95
    All 3 passes — pass 1 is the card above
    passi
    10
    21
    32
  7. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Alice"; //@lookupName="Alice", "Bob", "Charlie"72System.out.println("  " + lookupNameAlice + "'s score: " + scores.get(lookupName));
  8. index ← 0

    pass 1 of 2
    53public V get(K keyAlice) {54    int index→ 0 = keys.indexOf(keyAlice);55    return index0 >= 0 ? values.get(index) : null;56}
  9. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Alice"; //@lookupName="Alice", "Bob", "Charlie"72System.out.println("  " + lookupNameAlice + "'s score: " + scores.get(lookupName));
    output  Alice's score: 95
  10. index ← 0

    pass 2 of 2
    53public V get(K keyAlice) {54    int index→ 0 = keys.indexOf(keyAlice);55    return index0 >= 0 ? values.get(index) : null;56}
  11. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Alice"; //@lookupName="Alice", "Bob", "Charlie"72System.out.println("  " + lookupNameAlice + "'s score: " + scores.get(lookupName));7374System.out.println("\nTriple class:");
    output  Alice's score: 95
    
    Triple class:
    
    Triple class:
  12. this.first ← Alice, this.second ← 20, this.third ← 3.8

    pass 1 of 2
    81public Triple(A firstAlice, B second20, C third3.8) {82    this.first→ Alice = firstAlice;83    this.second→ 20 = second20;84    this.third→ 3.8 = third3.8;85}
  13. public void display()

    pass 1 of 2
    91public void display() {92    System.out.println("  (" + firstAlice + ", " + second20 + ", " + third3.8 + ")");93}
    output  (Alice, 20, 3.8)
  14. this.first ← 8080, this.second ← localhost, this.third ← true

    pass 2 of 2
    81public Triple(A first8080, B secondlocalhost, C thirdtrue) {82    this.first→ 8080 = first8080;83    this.second→ localhost = secondlocalhost;84    this.third→ true = thirdtrue;85}
  15. public void display()

    pass 2 of 2
    91public void display() {92    System.out.println("  (" + first8080 + ", " + secondlocalhost + ", " + thirdtrue + ")");93}
    output  (8080, localhost, true)
  16. System.out.println(" Entry class:");

    104System.out.println("\nEntry class:");
    output
    Entry class:
    
    Entry class:
  17. this.key ← host, this.value ← localhost, this.timestamp ← 1000

    pass 1 of 2
    111public Entry(K keyhost, V valuelocalhost) {112    this.key→ host = keyhost;113    this.value→ localhost = valuelocalhost;114    this.timestamp→ 1000 = 1000L;115}
  18. config1.display();

    131Entry<String, String> config1 = new Entry<>("host", "localhost");132config1.display();
  19. public void display()

    pass 1 of 2
    125public void display() {126    System.out.println("  " + keyhost + ": " + valuelocalhost + 127                       " (ts: " + timestamp1000 + ")");128}
    output  host: localhost (ts: 1000)
  20. config1.display();

    131Entry<String, String> config1 = new Entry<>("host", "localhost");132config1.display();133134Entry<Integer, List<String>> userTags = 135    new Entry<>(101, Arrays.asList("admin", "active"));136userTags.display();
  21. this.key ← 101, this.value ← [admin, active], this.timestamp ← 1000

    pass 2 of 2
    111public Entry(K key101, V value[admin, active]) {112    this.key→ 101 = key101;113    this.value→ [admin, active] = value[admin, active];114    this.timestamp→ 1000 = 1000L;115}
  22. userTags ← ⟨MultipleTypeParams$1Entry A⟩

    134    Entry<Integer, List<String>> userTags→ ⟨MultipleTypeParams$1Entry A⟩ = 135        new Entry<>(101, Arrays.asList("admin", "active"));136    userTags.display();137}
  23. public void display()

    pass 2 of 2
    125public void display() {126    System.out.println("  " + key101 + ": " + value[admin, active] + 127                       " (ts: " + timestamp1000 + ")");128}
    output  101: [admin, active] (ts: 1000)
  24. userTags.display();

    135        new Entry<>(101, Arrays.asList("admin", "active"));136    userTags.display();137}
  1. public static void main(String[] args)

    26public static void main(String[] args) {27    System.out.println("Multiple type parameters:\n");
    outputMultiple type parameters:
    Multiple type parameters:
  2. this.key ← Alice, this.value ← 30

    pass 1 of 3
    8public Pair(K keyAlice, V value30) {9    this.key→ Alice = keyAlice;10    this.value→ 30 = value30;11}
    All 3 passes — pass 1 is the card above
    passkeyvaluethis.keythis.value
    1Alice30Alice30
    21Bob1Bob
    3Coffee3.5Coffee3.5
  3. public void display()

    pass 1 of 3
    21public void display() {22    System.out.println("  " + keyAlice + " -> " + value30);23}
    output  Alice -> 30
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1Alice30
    21Bob
    3Coffee3.5
  4. System.out.println(" Simple map:");

    42System.out.println("\nSimple map:");
    output
    Simple map:
    
    Simple map:
  5. public void put(K key, V value)

    pass 1 of 3
    48public void put(K keyAlice, V value95) {49    keys.add(keyAlice);50    values.add(value95);51}
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1Alice95
    2Bob87
    3Charlie92
  6. for (int i = 0; i < keys.size(); i++)

    pass 1 of 3
    58public void display() {59    for (int i0 = 0; i < keys.size(); i++) {60        System.out.println("  " + keys.get(i0) + " = " + values.get(i));61    }
    output  Alice = 95
    All 3 passes — pass 1 is the card above
    passi
    10
    21
    32
  7. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Bob";72System.out.println("  " + lookupNameBob + "'s score: " + scores.get(lookupName));
  8. index ← 1

    pass 1 of 2
    53public V get(K keyBob) {54    int index→ 1 = keys.indexOf(keyBob);55    return index1 >= 0 ? values.get(index) : null;56}
  9. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Bob";72System.out.println("  " + lookupNameBob + "'s score: " + scores.get(lookupName));
    output  Bob's score: 87
  10. index ← 1

    pass 2 of 2
    53public V get(K keyBob) {54    int index→ 1 = keys.indexOf(keyBob);55    return index1 >= 0 ? values.get(index) : null;56}
  11. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Bob";72System.out.println("  " + lookupNameBob + "'s score: " + scores.get(lookupName));7374System.out.println("\nTriple class:");
    output  Bob's score: 87
    
    Triple class:
    
    Triple class:
  12. this.first ← Alice, this.second ← 20, this.third ← 3.8

    pass 1 of 2
    81public Triple(A firstAlice, B second20, C third3.8) {82    this.first→ Alice = firstAlice;83    this.second→ 20 = second20;84    this.third→ 3.8 = third3.8;85}
  13. public void display()

    pass 1 of 2
    91public void display() {92    System.out.println("  (" + firstAlice + ", " + second20 + ", " + third3.8 + ")");93}
    output  (Alice, 20, 3.8)
  14. this.first ← 8080, this.second ← localhost, this.third ← true

    pass 2 of 2
    81public Triple(A first8080, B secondlocalhost, C thirdtrue) {82    this.first→ 8080 = first8080;83    this.second→ localhost = secondlocalhost;84    this.third→ true = thirdtrue;85}
  15. public void display()

    pass 2 of 2
    91public void display() {92    System.out.println("  (" + first8080 + ", " + secondlocalhost + ", " + thirdtrue + ")");93}
    output  (8080, localhost, true)
  16. System.out.println(" Entry class:");

    104System.out.println("\nEntry class:");
    output
    Entry class:
    
    Entry class:
  17. this.key ← host, this.value ← localhost, this.timestamp ← 1000

    pass 1 of 2
    111public Entry(K keyhost, V valuelocalhost) {112    this.key→ host = keyhost;113    this.value→ localhost = valuelocalhost;114    this.timestamp→ 1000 = 1000L;115}
  18. config1.display();

    131Entry<String, String> config1 = new Entry<>("host", "localhost");132config1.display();
  19. public void display()

    pass 1 of 2
    125public void display() {126    System.out.println("  " + keyhost + ": " + valuelocalhost + 127                       " (ts: " + timestamp1000 + ")");128}
    output  host: localhost (ts: 1000)
  20. config1.display();

    131Entry<String, String> config1 = new Entry<>("host", "localhost");132config1.display();133134Entry<Integer, List<String>> userTags = 135    new Entry<>(101, Arrays.asList("admin", "active"));136userTags.display();
  21. this.key ← 101, this.value ← [admin, active], this.timestamp ← 1000

    pass 2 of 2
    111public Entry(K key101, V value[admin, active]) {112    this.key→ 101 = key101;113    this.value→ [admin, active] = value[admin, active];114    this.timestamp→ 1000 = 1000L;115}
  22. userTags ← ⟨MultipleTypeParams$1Entry A⟩

    134    Entry<Integer, List<String>> userTags→ ⟨MultipleTypeParams$1Entry A⟩ = 135        new Entry<>(101, Arrays.asList("admin", "active"));136    userTags.display();137}
  23. public void display()

    pass 2 of 2
    125public void display() {126    System.out.println("  " + key101 + ": " + value[admin, active] + 127                       " (ts: " + timestamp1000 + ")");128}
    output  101: [admin, active] (ts: 1000)
  24. userTags.display();

    135        new Entry<>(101, Arrays.asList("admin", "active"));136    userTags.display();137}
  1. public static void main(String[] args)

    26public static void main(String[] args) {27    System.out.println("Multiple type parameters:\n");
    outputMultiple type parameters:
    Multiple type parameters:
  2. this.key ← Alice, this.value ← 30

    pass 1 of 3
    8public Pair(K keyAlice, V value30) {9    this.key→ Alice = keyAlice;10    this.value→ 30 = value30;11}
    All 3 passes — pass 1 is the card above
    passkeyvaluethis.keythis.value
    1Alice30Alice30
    21Bob1Bob
    3Coffee3.5Coffee3.5
  3. public void display()

    pass 1 of 3
    21public void display() {22    System.out.println("  " + keyAlice + " -> " + value30);23}
    output  Alice -> 30
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1Alice30
    21Bob
    3Coffee3.5
  4. System.out.println(" Simple map:");

    42System.out.println("\nSimple map:");
    output
    Simple map:
    
    Simple map:
  5. public void put(K key, V value)

    pass 1 of 3
    48public void put(K keyAlice, V value95) {49    keys.add(keyAlice);50    values.add(value95);51}
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1Alice95
    2Bob87
    3Charlie92
  6. for (int i = 0; i < keys.size(); i++)

    pass 1 of 3
    58public void display() {59    for (int i0 = 0; i < keys.size(); i++) {60        System.out.println("  " + keys.get(i0) + " = " + values.get(i));61    }
    output  Alice = 95
    All 3 passes — pass 1 is the card above
    passi
    10
    21
    32
  7. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Charlie";72System.out.println("  " + lookupNameCharlie + "'s score: " + scores.get(lookupName));
  8. index ← 2

    pass 1 of 2
    53public V get(K keyCharlie) {54    int index→ 2 = keys.indexOf(keyCharlie);55    return index2 >= 0 ? values.get(index) : null;56}
  9. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Charlie";72System.out.println("  " + lookupNameCharlie + "'s score: " + scores.get(lookupName));
    output  Charlie's score: 92
  10. index ← 2

    pass 2 of 2
    53public V get(K keyCharlie) {54    int index→ 2 = keys.indexOf(keyCharlie);55    return index2 >= 0 ? values.get(index) : null;56}
  11. System.out.println(" " + lookupName + "'s score: " + scores.get(looku…

    71String lookupName = "Charlie";72System.out.println("  " + lookupNameCharlie + "'s score: " + scores.get(lookupName));7374System.out.println("\nTriple class:");
    output  Charlie's score: 92
    
    Triple class:
    
    Triple class:
  12. this.first ← Alice, this.second ← 20, this.third ← 3.8

    pass 1 of 2
    81public Triple(A firstAlice, B second20, C third3.8) {82    this.first→ Alice = firstAlice;83    this.second→ 20 = second20;84    this.third→ 3.8 = third3.8;85}
  13. public void display()

    pass 1 of 2
    91public void display() {92    System.out.println("  (" + firstAlice + ", " + second20 + ", " + third3.8 + ")");93}
    output  (Alice, 20, 3.8)
  14. this.first ← 8080, this.second ← localhost, this.third ← true

    pass 2 of 2
    81public Triple(A first8080, B secondlocalhost, C thirdtrue) {82    this.first→ 8080 = first8080;83    this.second→ localhost = secondlocalhost;84    this.third→ true = thirdtrue;85}
  15. public void display()

    pass 2 of 2
    91public void display() {92    System.out.println("  (" + first8080 + ", " + secondlocalhost + ", " + thirdtrue + ")");93}
    output  (8080, localhost, true)
  16. System.out.println(" Entry class:");

    104System.out.println("\nEntry class:");
    output
    Entry class:
    
    Entry class:
  17. this.key ← host, this.value ← localhost, this.timestamp ← 1000

    pass 1 of 2
    111public Entry(K keyhost, V valuelocalhost) {112    this.key→ host = keyhost;113    this.value→ localhost = valuelocalhost;114    this.timestamp→ 1000 = 1000L;115}
  18. config1.display();

    131Entry<String, String> config1 = new Entry<>("host", "localhost");132config1.display();
  19. public void display()

    pass 1 of 2
    125public void display() {126    System.out.println("  " + keyhost + ": " + valuelocalhost + 127                       " (ts: " + timestamp1000 + ")");128}
    output  host: localhost (ts: 1000)
  20. config1.display();

    131Entry<String, String> config1 = new Entry<>("host", "localhost");132config1.display();133134Entry<Integer, List<String>> userTags = 135    new Entry<>(101, Arrays.asList("admin", "active"));136userTags.display();
  21. this.key ← 101, this.value ← [admin, active], this.timestamp ← 1000

    pass 2 of 2
    111public Entry(K key101, V value[admin, active]) {112    this.key→ 101 = key101;113    this.value→ [admin, active] = value[admin, active];114    this.timestamp→ 1000 = 1000L;115}
  22. userTags ← ⟨MultipleTypeParams$1Entry A⟩

    134    Entry<Integer, List<String>> userTags→ ⟨MultipleTypeParams$1Entry A⟩ = 135        new Entry<>(101, Arrays.asList("admin", "active"));136    userTags.display();137}
  23. public void display()

    pass 2 of 2
    125public void display() {126    System.out.println("  " + key101 + ": " + value[admin, active] + 127                       " (ts: " + timestamp1000 + ")");128}
    output  101: [admin, active] (ts: 1000)
  24. userTags.display();

    135        new Entry<>(101, Arrays.asList("admin", "active"));136    userTags.display();137}

class Pair<K, V> - K for key, V for value. Like Map entries.

type parameter Placeholder for type: T, E, K, V. Convention: T=Type, E=Element, K=Key, V=Value.

Generic interface

Define interfaces with type parameters.

lookupId
GenericInterface.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class GenericInterface {
    interface Container<T> {
        void add(T item);
        T get(int index);
        int size();
        boolean isEmpty();
    }

    static class ListContainer<T> implements Container<T> {
        private List<T> items = new ArrayList<>();

        @Override
        public void add(T item) {
            items.add(item);
            System.out.println("  Added: " + item);
        }

        @Override
        public T get(int index) {
            return items.get(index);
        }

        @Override
        public int size() {
            return items.size();
        }

        @Override
        public boolean isEmpty() {
            return items.isEmpty();
        }
    }

    public static void main(String[] args) {
        System.out.println("Generic interface:\n");

        Container<String> strContainer = new ListContainer<>();
        strContainer.add("Apple");
        strContainer.add("Banana");
        strContainer.add("Cherry");

        System.out.println("  Size: " + strContainer.size());
        System.out.println("  First: " + strContainer.get(0));

        // Interfaces can have type parameters
        // Implementing class specifies type or remains generic
        // Same type safety benefits as generic classes

        System.out.println("\nStorage interface:");

        interface Storage<T> {
            void store(T item);
            T retrieve();
            void clear();
        }

        class MemoryStorage<T> implements Storage<T> {
            private T item;

            @Override
            public void store(T item) {
                this.item = item;
                System.out.println("  Stored: " + item);
            }

            @Override
            public T retrieve() {
                return item;
            }

            @Override
            public void clear() {
                item = null;
                System.out.println("  Cleared");
            }
        }

        Storage<Integer> intStorage = new MemoryStorage<>();
        intStorage.store(42);
        int value = intStorage.retrieve();
        System.out.println("  Retrieved: " + value);

        System.out.println("\nConcrete implementation:");

        class StringContainer implements Container<String> {
            private List<String> items = new ArrayList<>();

            @Override
            public void add(String item) {
                items.add(item.toUpperCase());
                System.out.println("  Added (upper): " + item);
            }

            @Override
            public String get(int index) {
                return items.get(index);
            }

            @Override
            public int size() {
                return items.size();
            }

            @Override
            public boolean isEmpty() {
                return items.isEmpty();
            }
        }

        Container<String> concrete = new StringContainer();
        concrete.add("hello");
        concrete.add("world");
        System.out.println("  First: " + concrete.get(0));

        System.out.println("\nComparable-like:");

        interface Comparable<T> {
            int compareTo(T other);
        }

        class Person implements Comparable<Person> {
            String name;
            int age;

            Person(String name, int age) {
                this.name = name;
                this.age = age;
            }

            @Override
            public int compareTo(Person other) {
                return Integer.compare(this.age, other.age);
            }

            @Override
            public String toString() {
                return name + " (" + age + ")";
            }
        }

        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Bob", 25);

        int result = p1.compareTo(p2);
        System.out.println("  " + p1 + " vs " + p2 + ": " + result);

        System.out.println("\nRepository pattern:");

        interface Repository<T, ID> {
            void save(T entity);
            T findById(ID id);
        }

        class UserRepository implements Repository<String, Integer> {
            private Map<Integer, String> users = new HashMap<>();

            @Override
            public void save(String user) {
                int id = users.size() + 1;
                users.put(id, user);
                System.out.println("  Saved user: " + user + " (id=" + id + ")");
            }

            @Override
            public String findById(Integer id) {
                return users.get(id);
            }
        }

        Repository<String, Integer> repo = new UserRepository();
        repo.save("Alice");
        repo.save("Bob");
        int lookupId = 1;
        String user = repo.findById(lookupId);
        System.out.println("  User " + lookupId + ": " + user);
    }
}
import java.util.*;

public class GenericInterface {
    interface Container<T> {
        void add(T item);
        T get(int index);
        int size();
        boolean isEmpty();
    }

    static class ListContainer<T> implements Container<T> {
        private List<T> items = new ArrayList<>();

        @Override
        public void add(T item) {
            items.add(item);
            System.out.println("  Added: " + item);
        }

        @Override
        public T get(int index) {
            return items.get(index);
        }

        @Override
        public int size() {
            return items.size();
        }

        @Override
        public boolean isEmpty() {
            return items.isEmpty();
        }
    }

    public static void main(String[] args) {
        System.out.println("Generic interface:\n");

        Container<String> strContainer = new ListContainer<>();
        strContainer.add("Apple");
        strContainer.add("Banana");
        strContainer.add("Cherry");

        System.out.println("  Size: " + strContainer.size());
        System.out.println("  First: " + strContainer.get(0));

        // Interfaces can have type parameters
        // Implementing class specifies type or remains generic
        // Same type safety benefits as generic classes

        System.out.println("\nStorage interface:");

        interface Storage<T> {
            void store(T item);
            T retrieve();
            void clear();
        }

        class MemoryStorage<T> implements Storage<T> {
            private T item;

            @Override
            public void store(T item) {
                this.item = item;
                System.out.println("  Stored: " + item);
            }

            @Override
            public T retrieve() {
                return item;
            }

            @Override
            public void clear() {
                item = null;
                System.out.println("  Cleared");
            }
        }

        Storage<Integer> intStorage = new MemoryStorage<>();
        intStorage.store(42);
        int value = intStorage.retrieve();
        System.out.println("  Retrieved: " + value);

        System.out.println("\nConcrete implementation:");

        class StringContainer implements Container<String> {
            private List<String> items = new ArrayList<>();

            @Override
            public void add(String item) {
                items.add(item.toUpperCase());
                System.out.println("  Added (upper): " + item);
            }

            @Override
            public String get(int index) {
                return items.get(index);
            }

            @Override
            public int size() {
                return items.size();
            }

            @Override
            public boolean isEmpty() {
                return items.isEmpty();
            }
        }

        Container<String> concrete = new StringContainer();
        concrete.add("hello");
        concrete.add("world");
        System.out.println("  First: " + concrete.get(0));

        System.out.println("\nComparable-like:");

        interface Comparable<T> {
            int compareTo(T other);
        }

        class Person implements Comparable<Person> {
            String name;
            int age;

            Person(String name, int age) {
                this.name = name;
                this.age = age;
            }

            @Override
            public int compareTo(Person other) {
                return Integer.compare(this.age, other.age);
            }

            @Override
            public String toString() {
                return name + " (" + age + ")";
            }
        }

        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Bob", 25);

        int result = p1.compareTo(p2);
        System.out.println("  " + p1 + " vs " + p2 + ": " + result);

        System.out.println("\nRepository pattern:");

        interface Repository<T, ID> {
            void save(T entity);
            T findById(ID id);
        }

        class UserRepository implements Repository<String, Integer> {
            private Map<Integer, String> users = new HashMap<>();

            @Override
            public void save(String user) {
                int id = users.size() + 1;
                users.put(id, user);
                System.out.println("  Saved user: " + user + " (id=" + id + ")");
            }

            @Override
            public String findById(Integer id) {
                return users.get(id);
            }
        }

        Repository<String, Integer> repo = new UserRepository();
        repo.save("Alice");
        repo.save("Bob");
        int lookupId = 2;
        String user = repo.findById(lookupId);
        System.out.println("  User " + lookupId + ": " + user);
    }
}
import java.util.*;

public class GenericInterface {
    interface Container<T> {
        void add(T item);
        T get(int index);
        int size();
        boolean isEmpty();
    }

    static class ListContainer<T> implements Container<T> {
        private List<T> items = new ArrayList<>();

        @Override
        public void add(T item) {
            items.add(item);
            System.out.println("  Added: " + item);
        }

        @Override
        public T get(int index) {
            return items.get(index);
        }

        @Override
        public int size() {
            return items.size();
        }

        @Override
        public boolean isEmpty() {
            return items.isEmpty();
        }
    }

    public static void main(String[] args) {
        System.out.println("Generic interface:\n");

        Container<String> strContainer = new ListContainer<>();
        strContainer.add("Apple");
        strContainer.add("Banana");
        strContainer.add("Cherry");

        System.out.println("  Size: " + strContainer.size());
        System.out.println("  First: " + strContainer.get(0));

        // Interfaces can have type parameters
        // Implementing class specifies type or remains generic
        // Same type safety benefits as generic classes

        System.out.println("\nStorage interface:");

        interface Storage<T> {
            void store(T item);
            T retrieve();
            void clear();
        }

        class MemoryStorage<T> implements Storage<T> {
            private T item;

            @Override
            public void store(T item) {
                this.item = item;
                System.out.println("  Stored: " + item);
            }

            @Override
            public T retrieve() {
                return item;
            }

            @Override
            public void clear() {
                item = null;
                System.out.println("  Cleared");
            }
        }

        Storage<Integer> intStorage = new MemoryStorage<>();
        intStorage.store(42);
        int value = intStorage.retrieve();
        System.out.println("  Retrieved: " + value);

        System.out.println("\nConcrete implementation:");

        class StringContainer implements Container<String> {
            private List<String> items = new ArrayList<>();

            @Override
            public void add(String item) {
                items.add(item.toUpperCase());
                System.out.println("  Added (upper): " + item);
            }

            @Override
            public String get(int index) {
                return items.get(index);
            }

            @Override
            public int size() {
                return items.size();
            }

            @Override
            public boolean isEmpty() {
                return items.isEmpty();
            }
        }

        Container<String> concrete = new StringContainer();
        concrete.add("hello");
        concrete.add("world");
        System.out.println("  First: " + concrete.get(0));

        System.out.println("\nComparable-like:");

        interface Comparable<T> {
            int compareTo(T other);
        }

        class Person implements Comparable<Person> {
            String name;
            int age;

            Person(String name, int age) {
                this.name = name;
                this.age = age;
            }

            @Override
            public int compareTo(Person other) {
                return Integer.compare(this.age, other.age);
            }

            @Override
            public String toString() {
                return name + " (" + age + ")";
            }
        }

        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Bob", 25);

        int result = p1.compareTo(p2);
        System.out.println("  " + p1 + " vs " + p2 + ": " + result);

        System.out.println("\nRepository pattern:");

        interface Repository<T, ID> {
            void save(T entity);
            T findById(ID id);
        }

        class UserRepository implements Repository<String, Integer> {
            private Map<Integer, String> users = new HashMap<>();

            @Override
            public void save(String user) {
                int id = users.size() + 1;
                users.put(id, user);
                System.out.println("  Saved user: " + user + " (id=" + id + ")");
            }

            @Override
            public String findById(Integer id) {
                return users.get(id);
            }
        }

        Repository<String, Integer> repo = new UserRepository();
        repo.save("Alice");
        repo.save("Bob");
        int lookupId = 3;
        String user = repo.findById(lookupId);
        System.out.println("  User " + lookupId + ": " + user);
    }
}
  1. strContainer ← ⟨GenericInterface$ListContainer A⟩

    36public static void main(String[] args) {37    System.out.println("Generic interface:\n");38    39    Container<String> strContainer→ ⟨GenericInterface$ListContainer A⟩ = new ListContainer<>();40    strContainer.add("Apple");41    strContainer.add("Banana");
    outputGeneric interface:
  2. @Override public void add(T item)

    pass 1 of 3
    14@Override15public void add(T itemApple) {16    items.add(itemApple);17    System.out.println("  Added: " + itemApple);18}
    output  Added: Apple
    All 3 passes — pass 1 is the card above
    passitem
    1Apple
    2Banana
    3Cherry
  3. strContainer.add("Apple");

    39Container<String> strContainer = new ListContainer<>();40strContainer.add("Apple");41strContainer.add("Banana");42strContainer.add("Cherry");
  4. strContainer.add("Banana");

    40strContainer.add("Apple");41strContainer.add("Banana");42strContainer.add("Cherry");
  5. strContainer.add("Cherry");

    41strContainer.add("Banana");42strContainer.add("Cherry");4344System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));
  6. System.out.println(" Size: " + strContainer.size());

    44System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));
    output  Size: 3
  7. @Override public T get(int index)

    20@Override21public T get(int index0) {22    return items.get(index0);23}
  8. System.out.println(" First: " + strContainer.get(0));

    44System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));4647// Interfaces can have type parameters48// Implementing class specifies type or remains generic49// Same type safety benefits as generic classes5051System.out.println("\nStorage interface:");
    output  First: Apple
    
    Storage interface:
  9. this.item ← 42

    62@Override63public void store(T item42) {64    this.item→ 42 = item42;65    System.out.println("  Stored: " + item42);66}
    output  Stored: 42
  10. @Override public T retrieve()

    68@Override69public T retrieve() {70    return item42;71}
  11. System.out.println(" Retrieved: " + value);

    82int value = intStorage.retrieve();83System.out.println("  Retrieved: " + value42);8485System.out.println("\nConcrete implementation:");8687class StringContainer implements Container<String> {88    private List<String> items = new ArrayList<>();89    90    @Override91    public void add(String item) {92        items.add(item.toUpperCase());93        System.out.println("  Added (upper): " + item);94    }95    96    @Override97    public String get(int index) {98        return items.get(index);99    }100    101    @Override102    public int size() {103        return items.size();104    }105    106    @Override107    public boolean isEmpty() {108        return items.isEmpty();109    }110}111112Container<String> concrete = new StringContainer();113concrete.add("hello");114concrete.add("world");
    output  Retrieved: 42
      Retrieved: 42
    
    Concrete implementation:
    
    Concrete implementation:
  12. @Override public void add(String item)

    pass 1 of 2
    90@Override91public void add(String itemhello) {92    items.add(item.toUpperCase());93    System.out.println("  Added (upper): " + itemhello);94}
    output  Added (upper): hello
  13. concrete.add("hello");

    112Container<String> concrete = new StringContainer();113concrete.add("hello");114concrete.add("world");115System.out.println("  First: " + concrete.get(0));
  14. @Override public void add(String item)

    pass 2 of 2
    90@Override91public void add(String itemworld) {92    items.add(item.toUpperCase());93    System.out.println("  Added (upper): " + itemworld);94}
    output  Added (upper): world
  15. concrete.add("world");

    113concrete.add("hello");114concrete.add("world");115System.out.println("  First: " + concrete.get(0));
  16. @Override public String get(int index)

    96@Override97public String get(int index0) {98    return items.get(index0);99}
  17. System.out.println(" First: " + concrete.get(0));

    114concrete.add("world");115System.out.println("  First: " + concrete.get(0));116117System.out.println("\nComparable-like:");
    output  First: HELLO
    
    Comparable-like:
  18. this.name ← Alice, this.age ← 30

    pass 1 of 2
    127Person(String nameAlice, int age30) {128    this.name→ Alice = nameAlice;129    this.age→ 30 = age30;130}
  19. Person p2 = new Person("Bob", 25);

    143Person p1 = new Person("Alice", 30);144Person p2 = new Person("Bob", 25);
  20. this.name ← Bob, this.age ← 25

    pass 2 of 2
    127Person(String nameBob, int age25) {128    this.name→ Bob = nameBob;129    this.age→ 25 = age25;130}
  21. p2 ← Bob (25)

    143Person p1 = new Person("Alice", 30);144Person p2→ Bob (25) = new Person("Bob", 25);145146int result = p1.compareTo(p2Bob (25));147System.out.println("  " + p1 + " vs " + p2 + ": " + result);
  22. @Override public int compareTo(Person other)

    132@Override133public int compareTo(Person otherBob (25)) {134    return Integer.compare(this.age30, other.age25);135}
  23. result ← 1

    146int result→ 1 = p1.compareTo(p2Bob (25));147System.out.println("  " + p1Alice (30) + " vs " + p2Bob (25) + ": " + result1);148149System.out.println("\nRepository pattern:");150151interface Repository<T, ID> {152    void save(T entity);153    T findById(ID id);154}155156class UserRepository implements Repository<String, Integer> {157    private Map<Integer, String> users = new HashMap<>();158    159    @Override160    public void save(String user) {161        int id = users.size() + 1;162        users.put(id, user);163        System.out.println("  Saved user: " + user + " (id=" + id + ")");164    }165    166    @Override167    public String findById(Integer id) {168        return users.get(id);169    }170}171172Repository<String, Integer> repo = new UserRepository();173repo.save("Alice");174repo.save("Bob");
    output  Alice (30) vs Bob (25): 1
    
    Repository pattern:
  24. id ← 1

    pass 1 of 2
    159@Override160public void save(String userAlice) {161    int id→ 1 = users.size() + 1;162    users.put(id1, userAlice);163    System.out.println("  Saved user: " + userAlice + " (id=" + id1 + ")");164}
    output  Saved user: Alice (id=1)
  25. repo.save("Alice");

    172Repository<String, Integer> repo = new UserRepository();173repo.save("Alice");174repo.save("Bob");175int lookupId = 1; //@lookupId=1, 2, 3
  26. id ← 2

    pass 2 of 2
    159@Override160public void save(String userBob) {161    int id→ 2 = users.size() + 1;162    users.put(id2, userBob);163    System.out.println("  Saved user: " + userBob + " (id=" + id2 + ")");164}
    output  Saved user: Bob (id=2)
  27. lookupId ← 1

    173repo.save("Alice");174repo.save("Bob");175int lookupId→ 1 = 1; //@lookupId=1, 2, 3176String user = repo.findById(lookupId1);177System.out.println("  User " + lookupId + ": " + user);
  28. @Override public String findById(Integer id)

    166@Override167public String findById(Integer id1) {168    return users.get(id1);169}
  29. user ← Alice

    175    int lookupId = 1; //@lookupId=1, 2, 3176    String user→ Alice = repo.findById(lookupId1);177    System.out.println("  User " + lookupId1 + ": " + userAlice);178}
    output  User 1: Alice
  1. strContainer ← ⟨GenericInterface$ListContainer A⟩

    36public static void main(String[] args) {37    System.out.println("Generic interface:\n");38    39    Container<String> strContainer→ ⟨GenericInterface$ListContainer A⟩ = new ListContainer<>();40    strContainer.add("Apple");41    strContainer.add("Banana");
    outputGeneric interface:
  2. @Override public void add(T item)

    pass 1 of 3
    14@Override15public void add(T itemApple) {16    items.add(itemApple);17    System.out.println("  Added: " + itemApple);18}
    output  Added: Apple
    All 3 passes — pass 1 is the card above
    passitem
    1Apple
    2Banana
    3Cherry
  3. strContainer.add("Apple");

    39Container<String> strContainer = new ListContainer<>();40strContainer.add("Apple");41strContainer.add("Banana");42strContainer.add("Cherry");
  4. strContainer.add("Banana");

    40strContainer.add("Apple");41strContainer.add("Banana");42strContainer.add("Cherry");
  5. strContainer.add("Cherry");

    41strContainer.add("Banana");42strContainer.add("Cherry");4344System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));
  6. System.out.println(" Size: " + strContainer.size());

    44System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));
    output  Size: 3
  7. @Override public T get(int index)

    20@Override21public T get(int index0) {22    return items.get(index0);23}
  8. System.out.println(" First: " + strContainer.get(0));

    44System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));4647// Interfaces can have type parameters48// Implementing class specifies type or remains generic49// Same type safety benefits as generic classes5051System.out.println("\nStorage interface:");
    output  First: Apple
    
    Storage interface:
  9. this.item ← 42

    62@Override63public void store(T item42) {64    this.item→ 42 = item42;65    System.out.println("  Stored: " + item42);66}
    output  Stored: 42
  10. @Override public T retrieve()

    68@Override69public T retrieve() {70    return item42;71}
  11. System.out.println(" Retrieved: " + value);

    82int value = intStorage.retrieve();83System.out.println("  Retrieved: " + value42);8485System.out.println("\nConcrete implementation:");8687class StringContainer implements Container<String> {88    private List<String> items = new ArrayList<>();89    90    @Override91    public void add(String item) {92        items.add(item.toUpperCase());93        System.out.println("  Added (upper): " + item);94    }95    96    @Override97    public String get(int index) {98        return items.get(index);99    }100    101    @Override102    public int size() {103        return items.size();104    }105    106    @Override107    public boolean isEmpty() {108        return items.isEmpty();109    }110}111112Container<String> concrete = new StringContainer();113concrete.add("hello");114concrete.add("world");
    output  Retrieved: 42
      Retrieved: 42
    
    Concrete implementation:
    
    Concrete implementation:
  12. @Override public void add(String item)

    pass 1 of 2
    90@Override91public void add(String itemhello) {92    items.add(item.toUpperCase());93    System.out.println("  Added (upper): " + itemhello);94}
    output  Added (upper): hello
  13. concrete.add("hello");

    112Container<String> concrete = new StringContainer();113concrete.add("hello");114concrete.add("world");115System.out.println("  First: " + concrete.get(0));
  14. @Override public void add(String item)

    pass 2 of 2
    90@Override91public void add(String itemworld) {92    items.add(item.toUpperCase());93    System.out.println("  Added (upper): " + itemworld);94}
    output  Added (upper): world
  15. concrete.add("world");

    113concrete.add("hello");114concrete.add("world");115System.out.println("  First: " + concrete.get(0));
  16. @Override public String get(int index)

    96@Override97public String get(int index0) {98    return items.get(index0);99}
  17. System.out.println(" First: " + concrete.get(0));

    114concrete.add("world");115System.out.println("  First: " + concrete.get(0));116117System.out.println("\nComparable-like:");
    output  First: HELLO
    
    Comparable-like:
  18. this.name ← Alice, this.age ← 30

    pass 1 of 2
    127Person(String nameAlice, int age30) {128    this.name→ Alice = nameAlice;129    this.age→ 30 = age30;130}
  19. Person p2 = new Person("Bob", 25);

    143Person p1 = new Person("Alice", 30);144Person p2 = new Person("Bob", 25);
  20. this.name ← Bob, this.age ← 25

    pass 2 of 2
    127Person(String nameBob, int age25) {128    this.name→ Bob = nameBob;129    this.age→ 25 = age25;130}
  21. p2 ← Bob (25)

    143Person p1 = new Person("Alice", 30);144Person p2→ Bob (25) = new Person("Bob", 25);145146int result = p1.compareTo(p2Bob (25));147System.out.println("  " + p1 + " vs " + p2 + ": " + result);
  22. @Override public int compareTo(Person other)

    132@Override133public int compareTo(Person otherBob (25)) {134    return Integer.compare(this.age30, other.age25);135}
  23. result ← 1

    146int result→ 1 = p1.compareTo(p2Bob (25));147System.out.println("  " + p1Alice (30) + " vs " + p2Bob (25) + ": " + result1);148149System.out.println("\nRepository pattern:");150151interface Repository<T, ID> {152    void save(T entity);153    T findById(ID id);154}155156class UserRepository implements Repository<String, Integer> {157    private Map<Integer, String> users = new HashMap<>();158    159    @Override160    public void save(String user) {161        int id = users.size() + 1;162        users.put(id, user);163        System.out.println("  Saved user: " + user + " (id=" + id + ")");164    }165    166    @Override167    public String findById(Integer id) {168        return users.get(id);169    }170}171172Repository<String, Integer> repo = new UserRepository();173repo.save("Alice");174repo.save("Bob");
    output  Alice (30) vs Bob (25): 1
    
    Repository pattern:
  24. id ← 1

    pass 1 of 2
    159@Override160public void save(String userAlice) {161    int id→ 1 = users.size() + 1;162    users.put(id1, userAlice);163    System.out.println("  Saved user: " + userAlice + " (id=" + id1 + ")");164}
    output  Saved user: Alice (id=1)
  25. repo.save("Alice");

    172Repository<String, Integer> repo = new UserRepository();173repo.save("Alice");174repo.save("Bob");175int lookupId = 2;
  26. id ← 2

    pass 2 of 2
    159@Override160public void save(String userBob) {161    int id→ 2 = users.size() + 1;162    users.put(id2, userBob);163    System.out.println("  Saved user: " + userBob + " (id=" + id2 + ")");164}
    output  Saved user: Bob (id=2)
  27. lookupId ← 2

    173repo.save("Alice");174repo.save("Bob");175int lookupId→ 2 = 2;176String user = repo.findById(lookupId2);177System.out.println("  User " + lookupId + ": " + user);
  28. @Override public String findById(Integer id)

    166@Override167public String findById(Integer id2) {168    return users.get(id2);169}
  29. user ← Bob

    175    int lookupId = 2;176    String user→ Bob = repo.findById(lookupId2);177    System.out.println("  User " + lookupId2 + ": " + userBob);178}
    output  User 2: Bob
  1. strContainer ← ⟨GenericInterface$ListContainer A⟩

    36public static void main(String[] args) {37    System.out.println("Generic interface:\n");38    39    Container<String> strContainer→ ⟨GenericInterface$ListContainer A⟩ = new ListContainer<>();40    strContainer.add("Apple");41    strContainer.add("Banana");
    outputGeneric interface:
  2. @Override public void add(T item)

    pass 1 of 3
    14@Override15public void add(T itemApple) {16    items.add(itemApple);17    System.out.println("  Added: " + itemApple);18}
    output  Added: Apple
    All 3 passes — pass 1 is the card above
    passitem
    1Apple
    2Banana
    3Cherry
  3. strContainer.add("Apple");

    39Container<String> strContainer = new ListContainer<>();40strContainer.add("Apple");41strContainer.add("Banana");42strContainer.add("Cherry");
  4. strContainer.add("Banana");

    40strContainer.add("Apple");41strContainer.add("Banana");42strContainer.add("Cherry");
  5. strContainer.add("Cherry");

    41strContainer.add("Banana");42strContainer.add("Cherry");4344System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));
  6. System.out.println(" Size: " + strContainer.size());

    44System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));
    output  Size: 3
  7. @Override public T get(int index)

    20@Override21public T get(int index0) {22    return items.get(index0);23}
  8. System.out.println(" First: " + strContainer.get(0));

    44System.out.println("  Size: " + strContainer.size());45System.out.println("  First: " + strContainer.get(0));4647// Interfaces can have type parameters48// Implementing class specifies type or remains generic49// Same type safety benefits as generic classes5051System.out.println("\nStorage interface:");
    output  First: Apple
    
    Storage interface:
  9. this.item ← 42

    62@Override63public void store(T item42) {64    this.item→ 42 = item42;65    System.out.println("  Stored: " + item42);66}
    output  Stored: 42
  10. @Override public T retrieve()

    68@Override69public T retrieve() {70    return item42;71}
  11. System.out.println(" Retrieved: " + value);

    82int value = intStorage.retrieve();83System.out.println("  Retrieved: " + value42);8485System.out.println("\nConcrete implementation:");8687class StringContainer implements Container<String> {88    private List<String> items = new ArrayList<>();89    90    @Override91    public void add(String item) {92        items.add(item.toUpperCase());93        System.out.println("  Added (upper): " + item);94    }95    96    @Override97    public String get(int index) {98        return items.get(index);99    }100    101    @Override102    public int size() {103        return items.size();104    }105    106    @Override107    public boolean isEmpty() {108        return items.isEmpty();109    }110}111112Container<String> concrete = new StringContainer();113concrete.add("hello");114concrete.add("world");
    output  Retrieved: 42
      Retrieved: 42
    
    Concrete implementation:
    
    Concrete implementation:
  12. @Override public void add(String item)

    pass 1 of 2
    90@Override91public void add(String itemhello) {92    items.add(item.toUpperCase());93    System.out.println("  Added (upper): " + itemhello);94}
    output  Added (upper): hello
  13. concrete.add("hello");

    112Container<String> concrete = new StringContainer();113concrete.add("hello");114concrete.add("world");115System.out.println("  First: " + concrete.get(0));
  14. @Override public void add(String item)

    pass 2 of 2
    90@Override91public void add(String itemworld) {92    items.add(item.toUpperCase());93    System.out.println("  Added (upper): " + itemworld);94}
    output  Added (upper): world
  15. concrete.add("world");

    113concrete.add("hello");114concrete.add("world");115System.out.println("  First: " + concrete.get(0));
  16. @Override public String get(int index)

    96@Override97public String get(int index0) {98    return items.get(index0);99}
  17. System.out.println(" First: " + concrete.get(0));

    114concrete.add("world");115System.out.println("  First: " + concrete.get(0));116117System.out.println("\nComparable-like:");
    output  First: HELLO
    
    Comparable-like:
  18. this.name ← Alice, this.age ← 30

    pass 1 of 2
    127Person(String nameAlice, int age30) {128    this.name→ Alice = nameAlice;129    this.age→ 30 = age30;130}
  19. Person p2 = new Person("Bob", 25);

    143Person p1 = new Person("Alice", 30);144Person p2 = new Person("Bob", 25);
  20. this.name ← Bob, this.age ← 25

    pass 2 of 2
    127Person(String nameBob, int age25) {128    this.name→ Bob = nameBob;129    this.age→ 25 = age25;130}
  21. p2 ← Bob (25)

    143Person p1 = new Person("Alice", 30);144Person p2→ Bob (25) = new Person("Bob", 25);145146int result = p1.compareTo(p2Bob (25));147System.out.println("  " + p1 + " vs " + p2 + ": " + result);
  22. @Override public int compareTo(Person other)

    132@Override133public int compareTo(Person otherBob (25)) {134    return Integer.compare(this.age30, other.age25);135}
  23. result ← 1

    146int result→ 1 = p1.compareTo(p2Bob (25));147System.out.println("  " + p1Alice (30) + " vs " + p2Bob (25) + ": " + result1);148149System.out.println("\nRepository pattern:");150151interface Repository<T, ID> {152    void save(T entity);153    T findById(ID id);154}155156class UserRepository implements Repository<String, Integer> {157    private Map<Integer, String> users = new HashMap<>();158    159    @Override160    public void save(String user) {161        int id = users.size() + 1;162        users.put(id, user);163        System.out.println("  Saved user: " + user + " (id=" + id + ")");164    }165    166    @Override167    public String findById(Integer id) {168        return users.get(id);169    }170}171172Repository<String, Integer> repo = new UserRepository();173repo.save("Alice");174repo.save("Bob");
    output  Alice (30) vs Bob (25): 1
    
    Repository pattern:
  24. id ← 1

    pass 1 of 2
    159@Override160public void save(String userAlice) {161    int id→ 1 = users.size() + 1;162    users.put(id1, userAlice);163    System.out.println("  Saved user: " + userAlice + " (id=" + id1 + ")");164}
    output  Saved user: Alice (id=1)
  25. repo.save("Alice");

    172Repository<String, Integer> repo = new UserRepository();173repo.save("Alice");174repo.save("Bob");175int lookupId = 3;
  26. id ← 2

    pass 2 of 2
    159@Override160public void save(String userBob) {161    int id→ 2 = users.size() + 1;162    users.put(id2, userBob);163    System.out.println("  Saved user: " + userBob + " (id=" + id2 + ")");164}
    output  Saved user: Bob (id=2)
  27. lookupId ← 3

    173repo.save("Alice");174repo.save("Bob");175int lookupId→ 3 = 3;176String user = repo.findById(lookupId3);177System.out.println("  User " + lookupId + ": " + user);
  28. @Override public String findById(Integer id)

    166@Override167public String findById(Integer id3) {168    return users.get(id3);169}
  29. user ← null

    175    int lookupId = 3;176    String user→ null = repo.findById(lookupId3);177    System.out.println("  User " + lookupId3 + ": " + usernull);178}
    output  User 3: null

interface Container<T> - implementations specify the type.

Diamond operator

Let compiler infer type arguments.

DiamondOperator.java
Replay: real traced execution (multi-file project)
import java.util.*;

public class DiamondOperator {
    static class Box<T> {
        private T value;

        public Box(T value) {
            this.value = value;
        }

        public T getValue() {
            return value;
        }
    }

    public static void main(String[] args) {
        System.out.println("Diamond operator:\n");

        // Before Java 7 (verbose)
        Box<String> box1 = new Box<String>("Hello");
        System.out.println("  Old way: " + box1.getValue());

        // Java 7+ (diamond operator)
        Box<String> box2 = new Box<>("World");
        System.out.println("  Diamond: " + box2.getValue());

        // Diamond operator <> infers type from left side
        // Available since Java 7
        // Reduces verbosity while maintaining type safety
        // Compiler infers the type parameter

        System.out.println("\nWith collections:");

        // Verbose
        List<String> list1 = new ArrayList<String>();
        list1.add("Apple");

        // Diamond
        List<String> list2 = new ArrayList<>();
        list2.add("Banana");

        Map<String, Integer> map = new LinkedHashMap<>();
        map.put("Alice", 30);
        map.put("Bob", 25);

        System.out.println("  List: " + list2);
        System.out.println("  Map: " + map);

        System.out.println("\nNested generics:");

        // Before Java 7 (very verbose)
        Map<String, List<Integer>> map1 =
            new HashMap<String, List<Integer>>();

        // With diamond (cleaner)
        Map<String, List<Integer>> map2 = new LinkedHashMap<>();
        map2.put("scores", Arrays.asList(85, 90, 95));
        map2.put("ages", Arrays.asList(20, 21, 22));

        System.out.println("  Nested map: " + map2);

        System.out.println("\nCustom classes:");

        class Pair<K, V> {
            K key;
            V value;

            Pair(K key, V value) {
                this.key = key;
                this.value = value;
            }

            @Override
            public String toString() {
                return key + "=" + value;
            }
        }

        // Diamond inference
        Pair<String, Integer> pair1 = new Pair<>("age", 30);
        Pair<Integer, String> pair2 = new Pair<>(1, "first");

        System.out.println("  " + pair1);
        System.out.println("  " + pair2);

        System.out.println("\nReturn type inference:");

        class Factory {
            static <T> Box<T> createBox(T value) {
                return new Box<>(value); // Diamond infers T
            }
        }

        Box<String> strBox = Factory.createBox("Hello");
        Box<Integer> intBox = Factory.createBox(42);

        System.out.println("  String box: " + strBox.getValue());
        System.out.println("  Integer box: " + intBox.getValue());

        System.out.println("\nComplex example:");

        class Container<T> {
            List<T> items;

            Container() {
                this.items = new ArrayList<>(); // Diamond
            }

            void add(T item) {
                items.add(item);
            }

            List<T> getItems() {
                return items;
            }
        }

        Container<String> container = new Container<>(); // Diamond
        container.add("A");
        container.add("B");
        container.add("C");

        System.out.println("  Items: " + container.getItems());

        // Nested
        List<Container<Integer>> containers = new ArrayList<>();
        Container<Integer> c1 = new Container<>();
        c1.add(1);
        c1.add(2);
        containers.add(c1);

        System.out.println("  Nested: " + containers.get(0).getItems());
    }
}
  1. public static void main(String[] args)

    16public static void main(String[] args) {17    System.out.println("Diamond operator:\n");
    outputDiamond operator:
    Diamond operator:
  2. this.value ← Hello

    pass 1 of 4
    7public Box(T valueHello) {8    this.value→ Hello = valueHello;9}
    All 4 passes — pass 1 is the card above
    passvaluethis.value
    1HelloHello
    2WorldWorld
    3HelloHello
    44242
  3. System.out.println(" Old way: " + box1.getValue());

    20Box<String> box1 = new Box<String>("Hello");21System.out.println("  Old way: " + box1.getValue());
  4. public T getValue()

    pass 1 of 8
    11public T getValue() {12    return valueHello;13}
    All 8 passes — pass 1 is the card above
    passvalue
    1Hello
    2Hello
    3World
    4World
    5Hello
    6Hello
    742
    842
  5. System.out.println(" Old way: " + box1.getValue());

    20Box<String> box1 = new Box<String>("Hello");21System.out.println("  Old way: " + box1.getValue());
    output  Old way: Hello
  6. System.out.println(" Old way: " + box1.getValue());

    20Box<String> box1 = new Box<String>("Hello");21System.out.println("  Old way: " + box1.getValue());
    output  Old way: Hello
  7. System.out.println(" Diamond: " + box2.getValue());

    24Box<String> box2 = new Box<>("World");25System.out.println("  Diamond: " + box2.getValue());
  8. System.out.println(" Diamond: " + box2.getValue());

    24Box<String> box2 = new Box<>("World");25System.out.println("  Diamond: " + box2.getValue());
    output  Diamond: World
  9. System.out.println(" List: " + list2);

    24Box<String> box2 = new Box<>("World");25System.out.println("  Diamond: " + box2.getValue());2627// Diamond operator <> infers type from left side28// Available since Java 729// Reduces verbosity while maintaining type safety30// Compiler infers the type parameter3132System.out.println("\nWith collections:");3334// Verbose35List<String> list1 = new ArrayList<String>();36list1.add("Apple");3738// Diamond39List<String> list2 = new ArrayList<>();40list2.add("Banana");4142Map<String, Integer> map = new LinkedHashMap<>();43map.put("Alice", 30);44map.put("Bob", 25);4546System.out.println("  List: " + list2[Banana]);47System.out.println("  Map: " + map{Alice=30, Bob=25});4849System.out.println("\nNested generics:");5051// Before Java 7 (very verbose)52Map<String, List<Integer>> map1 = 53    new HashMap<String, List<Integer>>();5455// With diamond (cleaner)56Map<String, List<Integer>> map2 = new LinkedHashMap<>();57map2.put("scores", Arrays.asList(85, 90, 95));58map2.put("ages", Arrays.asList(20, 21, 22));5960System.out.println("  Nested map: " + map2{scores=[85, 90, 95], ages=[20, 21, 22]});6162System.out.println("\nCustom classes:");
    output  Diamond: World
    
    With collections:
    
    With collections:
      List: [Banana]
      List: [Banana]
      Map: {Alice=30, Bob=25}
      Map: {Alice=30, Bob=25}
    
    Nested generics:
    
    Nested generics:
      Nested map: {scores=[85, 90, 95], ages=[20, 21, 22]}
      Nested map: {scores=[85, 90, 95], ages=[20, 21, 22]}
    
    Custom classes:
    
    Custom classes:
  10. this.key ← age, this.value ← 30

    pass 1 of 2
    68Pair(K keyage, V value30) {69    this.key→ age = keyage;70    this.value→ 30 = value30;71}
  11. this.key ← 1, this.value ← first

    pass 2 of 2
    68Pair(K key1, V valuefirst) {69    this.key→ 1 = key1;70    this.value→ first = valuefirst;71}
  12. System.out.println(" " + pair1);

    83System.out.println("  " + pair1age=30);84System.out.println("  " + pair21=first);8586System.out.println("\nReturn type inference:");
    output  age=30
      age=30
      1=first
      1=first
    
    Return type inference:
    
    Return type inference:
  13. static <T> Box<T> createBox(T value)

    pass 1 of 2
    88class Factory {89    static <T> Box<T> createBox(T valueHello) {90        return new Box<>(value); // Diamond infers T91    }
  14. static <T> Box<T> createBox(T value)

    pass 2 of 2
    88class Factory {89    static <T> Box<T> createBox(T value42) {90        return new Box<>(value); // Diamond infers T91    }
  15. System.out.println(" String box: " + strBox.getValue());

    97System.out.println("  String box: " + strBox.getValue());98System.out.println("  Integer box: " + intBox.getValue());
  16. System.out.println(" String box: " + strBox.getValue());

    97System.out.println("  String box: " + strBox.getValue());98System.out.println("  Integer box: " + intBox.getValue());
    output  String box: Hello
  17. System.out.println(" String box: " + strBox.getValue());

    97System.out.println("  String box: " + strBox.getValue());98System.out.println("  Integer box: " + intBox.getValue());
    output  String box: Hello
  18. System.out.println(" Integer box: " + intBox.getValue());

    97System.out.println("  String box: " + strBox.getValue());98System.out.println("  Integer box: " + intBox.getValue());
    output  Integer box: 42
  19. System.out.println(" Integer box: " + intBox.getValue());

    97System.out.println("  String box: " + strBox.getValue());98System.out.println("  Integer box: " + intBox.getValue());99100System.out.println("\nComplex example:");
    output  Integer box: 42
    
    Complex example:
    
    Complex example:
  20. this.items ← []

    pass 1 of 2
    105Container() {106    this.items→ [] = new ArrayList<>(); // Diamond107}
  21. container.add("A");

    118Container<String> container = new Container<>(); // Diamond119container.add("A");120container.add("B");
  22. void add(T item)

    pass 1 of 5
    109void add(T itemA) {110    items.add(itemA);111}
    All 5 passes — pass 1 is the card above
    passitem
    1A
    2B
    3C
    41
    52
  23. container.add("A");

    118Container<String> container = new Container<>(); // Diamond119container.add("A");120container.add("B");121container.add("C");
  24. container.add("B");

    119container.add("A");120container.add("B");121container.add("C");
  25. container.add("C");

    120container.add("B");121container.add("C");122123System.out.println("  Items: " + container.getItems());
  26. List<T> getItems()

    pass 1 of 2
    113List<T> getItems() {114    return items[A, B, C];115}
  27. containers ← []

    123System.out.println("  Items: " + container.getItems());124125// Nested126List<Container<Integer>> containers→ [] = new ArrayList<>();127Container<Integer> c1 = new Container<>();128c1.add(1);
    output  Items: [A, B, C]
  28. this.items ← []

    pass 2 of 2
    105Container() {106    this.items→ [] = new ArrayList<>(); // Diamond107}
  29. c1 ← ⟨DiamondOperator$1Container A⟩

    126List<Container<Integer>> containers = new ArrayList<>();127Container<Integer> c1→ ⟨DiamondOperator$1Container A⟩ = new Container<>();128c1.add(1);129c1.add(2);
  30. c1.add(1);

    127Container<Integer> c1 = new Container<>();128c1.add(1);129c1.add(2);130containers.add(c1);
  31. containers.add(c1);

    128    c1.add(1);129    c1.add(2);130    containers.add(c1⟨DiamondOperator$1Container A⟩);131    132    System.out.println("  Nested: " + containers.get(0).getItems());133}
  32. List<T> getItems()

    pass 2 of 2
    113List<T> getItems() {114    return items[1, 2];115}
  33. System.out.println(" Nested: " + containers.get(0).getItems());

    132    System.out.println("  Nested: " + containers.get(0).getItems());133}
    output  Nested: [1, 2]

new Box<>() - compiler infers type from variable declaration.

diamond operator `<>` in constructor - compiler infers type. Shorter than repeating type.

Exercise: Practical.java

Build a type-safe stack using generics