Your generic method needs to call compareTo(). But T could be anything - the compiler won't allow it. With <T extends Comparable<T>>, you guarantee T has compareTo(), and the compiler lets you use it.

Upper bounds with extends

Restrict T to a type or its subtypes.

ageToCheck
UpperBounds.java
Replay: real traced execution (multi-file project)
public class UpperBounds {
    static class NumberBox<T extends Number> {
        private T value;

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

        public T getValue() {
            return value;
        }

        public double getDoubleValue() {
            return value.doubleValue(); // Can call Number methods
        }

        public boolean isPositive() {
            return value.doubleValue() > 0;
        }
    }

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

        NumberBox<Integer> intBox = new NumberBox<>(42);
        System.out.println("  Integer: " + intBox.getValue());
        System.out.println("  As double: " + intBox.getDoubleValue());
        System.out.println("  Positive: " + intBox.isPositive());

        NumberBox<Double> doubleBox = new NumberBox<>(3.14);
        System.out.println("  Double: " + doubleBox.getValue());
        System.out.println("  Positive: " + doubleBox.isPositive());

        // NumberBox<String> strBox = new NumberBox<>("text"); // Compile error

        // <T extends Type> means T must be Type or subclass/implementer
        // Enables calling methods from the bounded type
        // Number bound allows: intValue(), doubleValue(), etc.
        // Compile error if type doesn't satisfy bound

        System.out.println("\nComparable bound:");

        class Sorter<T extends Comparable<T>> {
            public T max(T a, T b) {
                return a.compareTo(b) > 0 ? a : b;
            }

            public T min(T a, T b) {
                return a.compareTo(b) < 0 ? a : b;
            }
        }

        Sorter<Integer> intSorter = new Sorter<>();
        System.out.println("  Max(5, 10): " + intSorter.max(5, 10));
        System.out.println("  Min(5, 10): " + intSorter.min(5, 10));

        Sorter<String> strSorter = new Sorter<>();
        System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));

        System.out.println("\nStatistics:");

        class Stats<T extends Number> {
            private java.util.List<T> numbers;

            public Stats(java.util.List<T> numbers) {
                this.numbers = numbers;
            }

            public double average() {
                double sum = 0;
                for (T num : numbers) {
                    sum += num.doubleValue();
                }
                return sum / numbers.size();
            }

            public double sum() {
                double total = 0;
                for (T num : numbers) {
                    total += num.doubleValue();
                }
                return total;
            }
        }

        Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));
        System.out.println("  Average: " + intStats.average());
        System.out.println("  Sum: " + intStats.sum());

        System.out.println("\nRange:");

        class Range<T extends Comparable<T>> {
            private T min;
            private T max;

            public Range(T min, T max) {
                this.min = min;
                this.max = max;
            }

            public boolean contains(T value) {
                return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;
            }

            public String toString() {
                return "[" + min + " - " + max + "]";
            }
        }

        Range<Integer> ageRange = new Range<>(18, 65);
        System.out.println("  Range: " + ageRange);
        int ageToCheck = 25;
        System.out.println("  Contains " + ageToCheck + ": " +
                         ageRange.contains(ageToCheck));
        System.out.println("  Contains 70: " + ageRange.contains(70));

        Range<String> nameRange = new Range<>("A", "M");
        System.out.println("  Name range: " + nameRange);
        System.out.println("  Contains Alice: " + nameRange.contains("Alice"));
        System.out.println("  Contains Steve: " + nameRange.contains("Steve"));
    }
}
public class UpperBounds {
    static class NumberBox<T extends Number> {
        private T value;

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

        public T getValue() {
            return value;
        }

        public double getDoubleValue() {
            return value.doubleValue(); // Can call Number methods
        }

        public boolean isPositive() {
            return value.doubleValue() > 0;
        }
    }

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

        NumberBox<Integer> intBox = new NumberBox<>(42);
        System.out.println("  Integer: " + intBox.getValue());
        System.out.println("  As double: " + intBox.getDoubleValue());
        System.out.println("  Positive: " + intBox.isPositive());

        NumberBox<Double> doubleBox = new NumberBox<>(3.14);
        System.out.println("  Double: " + doubleBox.getValue());
        System.out.println("  Positive: " + doubleBox.isPositive());

        // NumberBox<String> strBox = new NumberBox<>("text"); // Compile error

        // <T extends Type> means T must be Type or subclass/implementer
        // Enables calling methods from the bounded type
        // Number bound allows: intValue(), doubleValue(), etc.
        // Compile error if type doesn't satisfy bound

        System.out.println("\nComparable bound:");

        class Sorter<T extends Comparable<T>> {
            public T max(T a, T b) {
                return a.compareTo(b) > 0 ? a : b;
            }

            public T min(T a, T b) {
                return a.compareTo(b) < 0 ? a : b;
            }
        }

        Sorter<Integer> intSorter = new Sorter<>();
        System.out.println("  Max(5, 10): " + intSorter.max(5, 10));
        System.out.println("  Min(5, 10): " + intSorter.min(5, 10));

        Sorter<String> strSorter = new Sorter<>();
        System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));

        System.out.println("\nStatistics:");

        class Stats<T extends Number> {
            private java.util.List<T> numbers;

            public Stats(java.util.List<T> numbers) {
                this.numbers = numbers;
            }

            public double average() {
                double sum = 0;
                for (T num : numbers) {
                    sum += num.doubleValue();
                }
                return sum / numbers.size();
            }

            public double sum() {
                double total = 0;
                for (T num : numbers) {
                    total += num.doubleValue();
                }
                return total;
            }
        }

        Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));
        System.out.println("  Average: " + intStats.average());
        System.out.println("  Sum: " + intStats.sum());

        System.out.println("\nRange:");

        class Range<T extends Comparable<T>> {
            private T min;
            private T max;

            public Range(T min, T max) {
                this.min = min;
                this.max = max;
            }

            public boolean contains(T value) {
                return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;
            }

            public String toString() {
                return "[" + min + " - " + max + "]";
            }
        }

        Range<Integer> ageRange = new Range<>(18, 65);
        System.out.println("  Range: " + ageRange);
        int ageToCheck = 17;
        System.out.println("  Contains " + ageToCheck + ": " +
                         ageRange.contains(ageToCheck));
        System.out.println("  Contains 70: " + ageRange.contains(70));

        Range<String> nameRange = new Range<>("A", "M");
        System.out.println("  Name range: " + nameRange);
        System.out.println("  Contains Alice: " + nameRange.contains("Alice"));
        System.out.println("  Contains Steve: " + nameRange.contains("Steve"));
    }
}
public class UpperBounds {
    static class NumberBox<T extends Number> {
        private T value;

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

        public T getValue() {
            return value;
        }

        public double getDoubleValue() {
            return value.doubleValue(); // Can call Number methods
        }

        public boolean isPositive() {
            return value.doubleValue() > 0;
        }
    }

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

        NumberBox<Integer> intBox = new NumberBox<>(42);
        System.out.println("  Integer: " + intBox.getValue());
        System.out.println("  As double: " + intBox.getDoubleValue());
        System.out.println("  Positive: " + intBox.isPositive());

        NumberBox<Double> doubleBox = new NumberBox<>(3.14);
        System.out.println("  Double: " + doubleBox.getValue());
        System.out.println("  Positive: " + doubleBox.isPositive());

        // NumberBox<String> strBox = new NumberBox<>("text"); // Compile error

        // <T extends Type> means T must be Type or subclass/implementer
        // Enables calling methods from the bounded type
        // Number bound allows: intValue(), doubleValue(), etc.
        // Compile error if type doesn't satisfy bound

        System.out.println("\nComparable bound:");

        class Sorter<T extends Comparable<T>> {
            public T max(T a, T b) {
                return a.compareTo(b) > 0 ? a : b;
            }

            public T min(T a, T b) {
                return a.compareTo(b) < 0 ? a : b;
            }
        }

        Sorter<Integer> intSorter = new Sorter<>();
        System.out.println("  Max(5, 10): " + intSorter.max(5, 10));
        System.out.println("  Min(5, 10): " + intSorter.min(5, 10));

        Sorter<String> strSorter = new Sorter<>();
        System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));

        System.out.println("\nStatistics:");

        class Stats<T extends Number> {
            private java.util.List<T> numbers;

            public Stats(java.util.List<T> numbers) {
                this.numbers = numbers;
            }

            public double average() {
                double sum = 0;
                for (T num : numbers) {
                    sum += num.doubleValue();
                }
                return sum / numbers.size();
            }

            public double sum() {
                double total = 0;
                for (T num : numbers) {
                    total += num.doubleValue();
                }
                return total;
            }
        }

        Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));
        System.out.println("  Average: " + intStats.average());
        System.out.println("  Sum: " + intStats.sum());

        System.out.println("\nRange:");

        class Range<T extends Comparable<T>> {
            private T min;
            private T max;

            public Range(T min, T max) {
                this.min = min;
                this.max = max;
            }

            public boolean contains(T value) {
                return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;
            }

            public String toString() {
                return "[" + min + " - " + max + "]";
            }
        }

        Range<Integer> ageRange = new Range<>(18, 65);
        System.out.println("  Range: " + ageRange);
        int ageToCheck = 70;
        System.out.println("  Contains " + ageToCheck + ": " +
                         ageRange.contains(ageToCheck));
        System.out.println("  Contains 70: " + ageRange.contains(70));

        Range<String> nameRange = new Range<>("A", "M");
        System.out.println("  Name range: " + nameRange);
        System.out.println("  Contains Alice: " + nameRange.contains("Alice"));
        System.out.println("  Contains Steve: " + nameRange.contains("Steve"));
    }
}
  1. public static void main(String[] args)

    22public static void main(String[] args) {23    System.out.println("Upper bounds:\n");
    outputUpper bounds:
    Upper bounds:
  2. this.value ← 42

    pass 1 of 2
    5public NumberBox(T value42) {6    this.value→ 42 = value42;7}
  3. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());
  4. public T getValue()

    pass 1 of 4
    9public T getValue() {10    return value42;11}
    All 4 passes — pass 1 is the card above
    passvalue
    142
    242
    33.14
    43.14
  5. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());
    output  Integer: 42
  6. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Integer: 42
  7. System.out.println(" As double: " + intBox.getDoubleValue());

    26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  As double: 42.0
  8. System.out.println(" As double: " + intBox.getDoubleValue());

    26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  As double: 42.0
  9. System.out.println(" Positive: " + intBox.isPositive());

    27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Positive: true
  10. System.out.println(" Positive: " + intBox.isPositive());

    27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Positive: true
  11. this.value ← 3.14

    pass 2 of 2
    5public NumberBox(T value3.14) {6    this.value→ 3.14 = value3.14;7}
  12. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
  13. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Double: 3.14
  14. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Double: 3.14
  15. System.out.println(" Positive: " + doubleBox.isPositive());

    31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Positive: true
  16. System.out.println(" Positive: " + doubleBox.isPositive());

    31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());3334// NumberBox<String> strBox = new NumberBox<>("text"); // Compile error3536// <T extends Type> means T must be Type or subclass/implementer37// Enables calling methods from the bounded type38// Number bound allows: intValue(), doubleValue(), etc.39// Compile error if type doesn't satisfy bound4041System.out.println("\nComparable bound:");4243class Sorter<T extends Comparable<T>> {44    public T max(T a, T b) {45        return a.compareTo(b) > 0 ? a : b;46    }47    48    public T min(T a, T b) {49        return a.compareTo(b) < 0 ? a : b;50    }51}5253Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Positive: true
    
    Comparable bound:
    
    Comparable bound:
  17. public T max(T a, T b)

    pass 1 of 4
    43class Sorter<T extends Comparable<T>> {44    public T max(T a5, T b10) {45        return a.compareTo(b10) > 0 ? a5 : b;46    }
    All 4 passes — pass 1 is the card above
    passab
    1510
    2510
    3applebanana
    4applebanana
  18. System.out.println(" Max(5, 10): " + intSorter.max(5, 10));

    53Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Max(5, 10): 10
  19. System.out.println(" Max(5, 10): " + intSorter.max(5, 10));

    53Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Max(5, 10): 10
  20. public T min(T a, T b)

    pass 1 of 2
    48public T min(T a5, T b10) {49    return a.compareTo(b10) < 0 ? a5 : b;50}
  21. System.out.println(" Min(5, 10): " + intSorter.min(5, 10));

    54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Min(5, 10): 5
  22. public T min(T a, T b)

    pass 2 of 2
    48public T min(T a5, T b10) {49    return a.compareTo(b10) < 0 ? a5 : b;50}
  23. System.out.println(" Min(5, 10): " + intSorter.min(5, 10));

    54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));5657Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));
    output  Min(5, 10): 5
  24. System.out.println(" Max(apple, banana): " + strSorter.max("apple", "…

    57Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));
    output  Max(apple, banana): banana
  25. System.out.println(" Max(apple, banana): " + strSorter.max("apple", "…

    57Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));5960System.out.println("\nStatistics:");
    output  Max(apple, banana): banana
    
    Statistics:
    
    Statistics:
  26. this.numbers ← [10, 20, 30, 40]

    65public Stats(java.util.List<T> numbers[10, 20, 30, 40]) {66    this.numbers→ [10, 20, 30, 40] = numbers[10, 20, 30, 40];67}
  27. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
  28. sum ← 0.0

    pass 1 of 2
    69public double average() {70    double sum→ 0.0 = 0;71    for (T num : numbers) {
  29. sum ← 10.0

    pass 1 of 8
    70double sum = 0;71for (T num10 : numbers[10, 20, 30, 40]) {72    sum→ 10.0 += num.doubleValue();73}
    All 8 passes — pass 1 is the card above
    passnumsum
    1100.0 10.0
    22010.0 30.0
    33030.0 60.0
    44060.0 100.0
    5100.0 10.0
    62010.0 30.0
    73030.0 60.0
    84060.0 100.0
  30. return sum / numbers.size();

    73    }74    return sum100.0 / numbers.size();75}
  31. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Average: 25.0
  32. sum ← 0.0

    pass 2 of 2
    69public double average() {70    double sum→ 0.0 = 0;71    for (T num : numbers) {
  33. return sum / numbers.size();

    73    }74    return sum100.0 / numbers.size();75}
  34. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Average: 25.0
  35. total ← 0.0

    pass 1 of 2
    77public double sum() {78    double total→ 0.0 = 0;79    for (T num : numbers) {
  36. total ← 10.0

    pass 1 of 8
    78double total = 0;79for (T num10 : numbers[10, 20, 30, 40]) {80    total→ 10.0 += num.doubleValue();81}
    All 8 passes — pass 1 is the card above
    passnumtotal
    1100.0 10.0
    22010.0 30.0
    33030.0 60.0
    44060.0 100.0
    5100.0 10.0
    62010.0 30.0
    73030.0 60.0
    84060.0 100.0
  37. return total;

    81    }82    return total100.0;83}
  38. System.out.println(" Sum: " + intStats.sum());

    87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Sum: 100.0
  39. total ← 0.0

    pass 2 of 2
    77public double sum() {78    double total→ 0.0 = 0;79    for (T num : numbers) {
  40. return total;

    81    }82    return total100.0;83}
  41. System.out.println(" Sum: " + intStats.sum());

    87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());8990System.out.println("\nRange:");
    output  Sum: 100.0
    
    Range:
    
    Range:
  42. this.min ← 18, this.max ← 65

    pass 1 of 2
    96public Range(T min18, T max65) {97    this.min→ 18 = min18;98    this.max→ 65 = max65;99}
  43. ageToCheck ← 25

    110Range<Integer> ageRange = new Range<>(18, 65);111System.out.println("  Range: " + ageRange[18 - 65]);112int ageToCheck→ 25 = 25; //@ageToCheck=25, 17, 70113System.out.println("  Contains " + ageToCheck25 + ": " +114                 ageRange.contains(ageToCheck25));115System.out.println("  Contains 70: " + ageRange.contains(70));
    output  Range: [18 - 65]
  44. public boolean contains(T value)

    pass 1 of 4
    101public boolean contains(T value25) {102    return value.compareTo(min18) >= 0 && value.compareTo(max65) <= 0;103}
    All 4 passes — pass 1 is the card above
    passvalueminmax
    1251865
    2701865
    3AliceAM
    4SteveAM
  45. System.out.println(" Contains " + ageToCheck + ": " +

    112int ageToCheck = 25; //@ageToCheck=25, 17, 70113System.out.println("  Contains " + ageToCheck25 + ": " +114                 ageRange.contains(ageToCheck25));115System.out.println("  Contains 70: " + ageRange.contains(70));
    output  Contains 25: true
  46. System.out.println(" Contains 70: " + ageRange.contains(70));

    114                 ageRange.contains(ageToCheck));115System.out.println("  Contains 70: " + ageRange.contains(70));116117Range<String> nameRange = new Range<>("A", "M");118System.out.println("  Name range: " + nameRange);
    output  Contains 70: false
  47. this.min ← A, this.max ← M

    pass 2 of 2
    96public Range(T minA, T maxM) {97    this.min→ A = minA;98    this.max→ M = maxM;99}
  48. nameRange ← [A - M]

    117Range<String> nameRange→ [A - M] = new Range<>("A", "M");118System.out.println("  Name range: " + nameRange[A - M]);119System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120System.out.println("  Contains Steve: " + nameRange.contains("Steve"));
    output  Name range: [A - M]
  49. System.out.println(" Contains Alice: " + nameRange.contains("Alice"))…

    118    System.out.println("  Name range: " + nameRange);119    System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120    System.out.println("  Contains Steve: " + nameRange.contains("Steve"));121}
    output  Contains Alice: true
  50. System.out.println(" Contains Steve: " + nameRange.contains("Steve"))…

    119    System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120    System.out.println("  Contains Steve: " + nameRange.contains("Steve"));121}
    output  Contains Steve: false
  1. public static void main(String[] args)

    22public static void main(String[] args) {23    System.out.println("Upper bounds:\n");
    outputUpper bounds:
    Upper bounds:
  2. this.value ← 42

    pass 1 of 2
    5public NumberBox(T value42) {6    this.value→ 42 = value42;7}
  3. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());
  4. public T getValue()

    pass 1 of 4
    9public T getValue() {10    return value42;11}
    All 4 passes — pass 1 is the card above
    passvalue
    142
    242
    33.14
    43.14
  5. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());
    output  Integer: 42
  6. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Integer: 42
  7. System.out.println(" As double: " + intBox.getDoubleValue());

    26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  As double: 42.0
  8. System.out.println(" As double: " + intBox.getDoubleValue());

    26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  As double: 42.0
  9. System.out.println(" Positive: " + intBox.isPositive());

    27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Positive: true
  10. System.out.println(" Positive: " + intBox.isPositive());

    27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Positive: true
  11. this.value ← 3.14

    pass 2 of 2
    5public NumberBox(T value3.14) {6    this.value→ 3.14 = value3.14;7}
  12. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
  13. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Double: 3.14
  14. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Double: 3.14
  15. System.out.println(" Positive: " + doubleBox.isPositive());

    31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Positive: true
  16. System.out.println(" Positive: " + doubleBox.isPositive());

    31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());3334// NumberBox<String> strBox = new NumberBox<>("text"); // Compile error3536// <T extends Type> means T must be Type or subclass/implementer37// Enables calling methods from the bounded type38// Number bound allows: intValue(), doubleValue(), etc.39// Compile error if type doesn't satisfy bound4041System.out.println("\nComparable bound:");4243class Sorter<T extends Comparable<T>> {44    public T max(T a, T b) {45        return a.compareTo(b) > 0 ? a : b;46    }47    48    public T min(T a, T b) {49        return a.compareTo(b) < 0 ? a : b;50    }51}5253Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Positive: true
    
    Comparable bound:
    
    Comparable bound:
  17. public T max(T a, T b)

    pass 1 of 4
    43class Sorter<T extends Comparable<T>> {44    public T max(T a5, T b10) {45        return a.compareTo(b10) > 0 ? a5 : b;46    }
    All 4 passes — pass 1 is the card above
    passab
    1510
    2510
    3applebanana
    4applebanana
  18. System.out.println(" Max(5, 10): " + intSorter.max(5, 10));

    53Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Max(5, 10): 10
  19. System.out.println(" Max(5, 10): " + intSorter.max(5, 10));

    53Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Max(5, 10): 10
  20. public T min(T a, T b)

    pass 1 of 2
    48public T min(T a5, T b10) {49    return a.compareTo(b10) < 0 ? a5 : b;50}
  21. System.out.println(" Min(5, 10): " + intSorter.min(5, 10));

    54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Min(5, 10): 5
  22. public T min(T a, T b)

    pass 2 of 2
    48public T min(T a5, T b10) {49    return a.compareTo(b10) < 0 ? a5 : b;50}
  23. System.out.println(" Min(5, 10): " + intSorter.min(5, 10));

    54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));5657Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));
    output  Min(5, 10): 5
  24. System.out.println(" Max(apple, banana): " + strSorter.max("apple", "…

    57Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));
    output  Max(apple, banana): banana
  25. System.out.println(" Max(apple, banana): " + strSorter.max("apple", "…

    57Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));5960System.out.println("\nStatistics:");
    output  Max(apple, banana): banana
    
    Statistics:
    
    Statistics:
  26. this.numbers ← [10, 20, 30, 40]

    65public Stats(java.util.List<T> numbers[10, 20, 30, 40]) {66    this.numbers→ [10, 20, 30, 40] = numbers[10, 20, 30, 40];67}
  27. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
  28. sum ← 0.0

    pass 1 of 2
    69public double average() {70    double sum→ 0.0 = 0;71    for (T num : numbers) {
  29. sum ← 10.0

    pass 1 of 8
    70double sum = 0;71for (T num10 : numbers[10, 20, 30, 40]) {72    sum→ 10.0 += num.doubleValue();73}
    All 8 passes — pass 1 is the card above
    passnumsum
    1100.0 10.0
    22010.0 30.0
    33030.0 60.0
    44060.0 100.0
    5100.0 10.0
    62010.0 30.0
    73030.0 60.0
    84060.0 100.0
  30. return sum / numbers.size();

    73    }74    return sum100.0 / numbers.size();75}
  31. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Average: 25.0
  32. sum ← 0.0

    pass 2 of 2
    69public double average() {70    double sum→ 0.0 = 0;71    for (T num : numbers) {
  33. return sum / numbers.size();

    73    }74    return sum100.0 / numbers.size();75}
  34. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Average: 25.0
  35. total ← 0.0

    pass 1 of 2
    77public double sum() {78    double total→ 0.0 = 0;79    for (T num : numbers) {
  36. total ← 10.0

    pass 1 of 8
    78double total = 0;79for (T num10 : numbers[10, 20, 30, 40]) {80    total→ 10.0 += num.doubleValue();81}
    All 8 passes — pass 1 is the card above
    passnumtotal
    1100.0 10.0
    22010.0 30.0
    33030.0 60.0
    44060.0 100.0
    5100.0 10.0
    62010.0 30.0
    73030.0 60.0
    84060.0 100.0
  37. return total;

    81    }82    return total100.0;83}
  38. System.out.println(" Sum: " + intStats.sum());

    87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Sum: 100.0
  39. total ← 0.0

    pass 2 of 2
    77public double sum() {78    double total→ 0.0 = 0;79    for (T num : numbers) {
  40. return total;

    81    }82    return total100.0;83}
  41. System.out.println(" Sum: " + intStats.sum());

    87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());8990System.out.println("\nRange:");
    output  Sum: 100.0
    
    Range:
    
    Range:
  42. this.min ← 18, this.max ← 65

    pass 1 of 2
    96public Range(T min18, T max65) {97    this.min→ 18 = min18;98    this.max→ 65 = max65;99}
  43. ageToCheck ← 17

    110Range<Integer> ageRange = new Range<>(18, 65);111System.out.println("  Range: " + ageRange[18 - 65]);112int ageToCheck→ 17 = 17;113System.out.println("  Contains " + ageToCheck17 + ": " +114                 ageRange.contains(ageToCheck17));115System.out.println("  Contains 70: " + ageRange.contains(70));
    output  Range: [18 - 65]
  44. public boolean contains(T value)

    pass 1 of 4
    101public boolean contains(T value17) {102    return value.compareTo(min18) >= 0 && value.compareTo(max65) <= 0;103}
    All 4 passes — pass 1 is the card above
    passvalueminmax
    1171865
    2701865
    3AliceAM
    4SteveAM
  45. System.out.println(" Contains " + ageToCheck + ": " +

    112int ageToCheck = 17;113System.out.println("  Contains " + ageToCheck17 + ": " +114                 ageRange.contains(ageToCheck17));115System.out.println("  Contains 70: " + ageRange.contains(70));
    output  Contains 17: false
  46. System.out.println(" Contains 70: " + ageRange.contains(70));

    114                 ageRange.contains(ageToCheck));115System.out.println("  Contains 70: " + ageRange.contains(70));116117Range<String> nameRange = new Range<>("A", "M");118System.out.println("  Name range: " + nameRange);
    output  Contains 70: false
  47. this.min ← A, this.max ← M

    pass 2 of 2
    96public Range(T minA, T maxM) {97    this.min→ A = minA;98    this.max→ M = maxM;99}
  48. nameRange ← [A - M]

    117Range<String> nameRange→ [A - M] = new Range<>("A", "M");118System.out.println("  Name range: " + nameRange[A - M]);119System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120System.out.println("  Contains Steve: " + nameRange.contains("Steve"));
    output  Name range: [A - M]
  49. System.out.println(" Contains Alice: " + nameRange.contains("Alice"))…

    118    System.out.println("  Name range: " + nameRange);119    System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120    System.out.println("  Contains Steve: " + nameRange.contains("Steve"));121}
    output  Contains Alice: true
  50. System.out.println(" Contains Steve: " + nameRange.contains("Steve"))…

    119    System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120    System.out.println("  Contains Steve: " + nameRange.contains("Steve"));121}
    output  Contains Steve: false
  1. public static void main(String[] args)

    22public static void main(String[] args) {23    System.out.println("Upper bounds:\n");
    outputUpper bounds:
    Upper bounds:
  2. this.value ← 42

    pass 1 of 2
    5public NumberBox(T value42) {6    this.value→ 42 = value42;7}
  3. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());
  4. public T getValue()

    pass 1 of 4
    9public T getValue() {10    return value42;11}
    All 4 passes — pass 1 is the card above
    passvalue
    142
    242
    33.14
    43.14
  5. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());
    output  Integer: 42
  6. System.out.println(" Integer: " + intBox.getValue());

    25NumberBox<Integer> intBox = new NumberBox<>(42);26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Integer: 42
  7. System.out.println(" As double: " + intBox.getDoubleValue());

    26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  As double: 42.0
  8. System.out.println(" As double: " + intBox.getDoubleValue());

    26System.out.println("  Integer: " + intBox.getValue());27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  As double: 42.0
  9. System.out.println(" Positive: " + intBox.isPositive());

    27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Positive: true
  10. System.out.println(" Positive: " + intBox.isPositive());

    27System.out.println("  As double: " + intBox.getDoubleValue());28System.out.println("  Positive: " + intBox.isPositive());
    output  Positive: true
  11. this.value ← 3.14

    pass 2 of 2
    5public NumberBox(T value3.14) {6    this.value→ 3.14 = value3.14;7}
  12. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
  13. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Double: 3.14
  14. System.out.println(" Double: " + doubleBox.getValue());

    30NumberBox<Double> doubleBox = new NumberBox<>(3.14);31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Double: 3.14
  15. System.out.println(" Positive: " + doubleBox.isPositive());

    31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());
    output  Positive: true
  16. System.out.println(" Positive: " + doubleBox.isPositive());

    31System.out.println("  Double: " + doubleBox.getValue());32System.out.println("  Positive: " + doubleBox.isPositive());3334// NumberBox<String> strBox = new NumberBox<>("text"); // Compile error3536// <T extends Type> means T must be Type or subclass/implementer37// Enables calling methods from the bounded type38// Number bound allows: intValue(), doubleValue(), etc.39// Compile error if type doesn't satisfy bound4041System.out.println("\nComparable bound:");4243class Sorter<T extends Comparable<T>> {44    public T max(T a, T b) {45        return a.compareTo(b) > 0 ? a : b;46    }47    48    public T min(T a, T b) {49        return a.compareTo(b) < 0 ? a : b;50    }51}5253Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Positive: true
    
    Comparable bound:
    
    Comparable bound:
  17. public T max(T a, T b)

    pass 1 of 4
    43class Sorter<T extends Comparable<T>> {44    public T max(T a5, T b10) {45        return a.compareTo(b10) > 0 ? a5 : b;46    }
    All 4 passes — pass 1 is the card above
    passab
    1510
    2510
    3applebanana
    4applebanana
  18. System.out.println(" Max(5, 10): " + intSorter.max(5, 10));

    53Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Max(5, 10): 10
  19. System.out.println(" Max(5, 10): " + intSorter.max(5, 10));

    53Sorter<Integer> intSorter = new Sorter<>();54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Max(5, 10): 10
  20. public T min(T a, T b)

    pass 1 of 2
    48public T min(T a5, T b10) {49    return a.compareTo(b10) < 0 ? a5 : b;50}
  21. System.out.println(" Min(5, 10): " + intSorter.min(5, 10));

    54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));
    output  Min(5, 10): 5
  22. public T min(T a, T b)

    pass 2 of 2
    48public T min(T a5, T b10) {49    return a.compareTo(b10) < 0 ? a5 : b;50}
  23. System.out.println(" Min(5, 10): " + intSorter.min(5, 10));

    54System.out.println("  Max(5, 10): " + intSorter.max(5, 10));55System.out.println("  Min(5, 10): " + intSorter.min(5, 10));5657Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));
    output  Min(5, 10): 5
  24. System.out.println(" Max(apple, banana): " + strSorter.max("apple", "…

    57Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));
    output  Max(apple, banana): banana
  25. System.out.println(" Max(apple, banana): " + strSorter.max("apple", "…

    57Sorter<String> strSorter = new Sorter<>();58System.out.println("  Max(apple, banana): " + strSorter.max("apple", "banana"));5960System.out.println("\nStatistics:");
    output  Max(apple, banana): banana
    
    Statistics:
    
    Statistics:
  26. this.numbers ← [10, 20, 30, 40]

    65public Stats(java.util.List<T> numbers[10, 20, 30, 40]) {66    this.numbers→ [10, 20, 30, 40] = numbers[10, 20, 30, 40];67}
  27. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
  28. sum ← 0.0

    pass 1 of 2
    69public double average() {70    double sum→ 0.0 = 0;71    for (T num : numbers) {
  29. sum ← 10.0

    pass 1 of 8
    70double sum = 0;71for (T num10 : numbers[10, 20, 30, 40]) {72    sum→ 10.0 += num.doubleValue();73}
    All 8 passes — pass 1 is the card above
    passnumsum
    1100.0 10.0
    22010.0 30.0
    33030.0 60.0
    44060.0 100.0
    5100.0 10.0
    62010.0 30.0
    73030.0 60.0
    84060.0 100.0
  30. return sum / numbers.size();

    73    }74    return sum100.0 / numbers.size();75}
  31. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Average: 25.0
  32. sum ← 0.0

    pass 2 of 2
    69public double average() {70    double sum→ 0.0 = 0;71    for (T num : numbers) {
  33. return sum / numbers.size();

    73    }74    return sum100.0 / numbers.size();75}
  34. System.out.println(" Average: " + intStats.average());

    86Stats<Integer> intStats = new Stats<>(java.util.Arrays.asList(10, 20, 30, 40));87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Average: 25.0
  35. total ← 0.0

    pass 1 of 2
    77public double sum() {78    double total→ 0.0 = 0;79    for (T num : numbers) {
  36. total ← 10.0

    pass 1 of 8
    78double total = 0;79for (T num10 : numbers[10, 20, 30, 40]) {80    total→ 10.0 += num.doubleValue();81}
    All 8 passes — pass 1 is the card above
    passnumtotal
    1100.0 10.0
    22010.0 30.0
    33030.0 60.0
    44060.0 100.0
    5100.0 10.0
    62010.0 30.0
    73030.0 60.0
    84060.0 100.0
  37. return total;

    81    }82    return total100.0;83}
  38. System.out.println(" Sum: " + intStats.sum());

    87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());
    output  Sum: 100.0
  39. total ← 0.0

    pass 2 of 2
    77public double sum() {78    double total→ 0.0 = 0;79    for (T num : numbers) {
  40. return total;

    81    }82    return total100.0;83}
  41. System.out.println(" Sum: " + intStats.sum());

    87System.out.println("  Average: " + intStats.average());88System.out.println("  Sum: " + intStats.sum());8990System.out.println("\nRange:");
    output  Sum: 100.0
    
    Range:
    
    Range:
  42. this.min ← 18, this.max ← 65

    pass 1 of 2
    96public Range(T min18, T max65) {97    this.min→ 18 = min18;98    this.max→ 65 = max65;99}
  43. ageToCheck ← 70

    110Range<Integer> ageRange = new Range<>(18, 65);111System.out.println("  Range: " + ageRange[18 - 65]);112int ageToCheck→ 70 = 70;113System.out.println("  Contains " + ageToCheck70 + ": " +114                 ageRange.contains(ageToCheck70));115System.out.println("  Contains 70: " + ageRange.contains(70));
    output  Range: [18 - 65]
  44. public boolean contains(T value)

    pass 1 of 4
    101public boolean contains(T value70) {102    return value.compareTo(min18) >= 0 && value.compareTo(max65) <= 0;103}
    All 4 passes — pass 1 is the card above
    passvalueminmax
    1701865
    2701865
    3AliceAM
    4SteveAM
  45. System.out.println(" Contains " + ageToCheck + ": " +

    112int ageToCheck = 70;113System.out.println("  Contains " + ageToCheck70 + ": " +114                 ageRange.contains(ageToCheck70));115System.out.println("  Contains 70: " + ageRange.contains(70));
    output  Contains 70: false
  46. System.out.println(" Contains 70: " + ageRange.contains(70));

    114                 ageRange.contains(ageToCheck));115System.out.println("  Contains 70: " + ageRange.contains(70));116117Range<String> nameRange = new Range<>("A", "M");118System.out.println("  Name range: " + nameRange);
    output  Contains 70: false
  47. this.min ← A, this.max ← M

    pass 2 of 2
    96public Range(T minA, T maxM) {97    this.min→ A = minA;98    this.max→ M = maxM;99}
  48. nameRange ← [A - M]

    117Range<String> nameRange→ [A - M] = new Range<>("A", "M");118System.out.println("  Name range: " + nameRange[A - M]);119System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120System.out.println("  Contains Steve: " + nameRange.contains("Steve"));
    output  Name range: [A - M]
  49. System.out.println(" Contains Alice: " + nameRange.contains("Alice"))…

    118    System.out.println("  Name range: " + nameRange);119    System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120    System.out.println("  Contains Steve: " + nameRange.contains("Steve"));121}
    output  Contains Alice: true
  50. System.out.println(" Contains Steve: " + nameRange.contains("Steve"))…

    119    System.out.println("  Contains Alice: " + nameRange.contains("Alice"));120    System.out.println("  Contains Steve: " + nameRange.contains("Steve"));121}
    output  Contains Steve: false

<T extends Number> - T must be Number or subclass. Can call Number methods.

upper bound `extends` constraint: `<T extends Type>`. T must be Type or subtype.

Multiple bounds

Combine class and interface constraints.

rangeValue
MultipleBounds.java
Replay: real traced execution (multi-file project)
import java.io.Serializable;

public class MultipleBounds {
    static class Calculator<T extends Number & Comparable<T>> {
        public T max(T a, T b) {
            return a.compareTo(b) > 0 ? a : b;
        }

        public double add(T a, T b) {
            return a.doubleValue() + b.doubleValue();
        }

        public boolean inRange(T value, T min, T max) {
            return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;
        }
    }

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

        Calculator<Integer> intCalc = new Calculator<>();
        System.out.println("  Max(5, 10): " + intCalc.max(5, 10));
        System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
        int rangeValue = 7;
        System.out.println("  InRange(" + rangeValue + ", 5, 10): " +
                         intCalc.inRange(rangeValue, 5, 10));

        Calculator<Double> doubleCalc = new Calculator<>();
        System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));

        // Multiple bounds: <T extends Type1 & Type2 & Type3>
        // Class bound must come first (can only have one class)
        // Interface bounds follow, separated by &
        // T must satisfy ALL bounds

        System.out.println("\nSerializable + Comparable:");

        class Storage<T extends Serializable & Comparable<T>> {
            private T value;

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

            public T retrieve() {
                return value;
            }

            public boolean isGreaterThan(T other) {
                return value != null && value.compareTo(other) > 0;
            }
        }

        Storage<String> strStorage = new Storage<>();
        strStorage.store("Hello");
        System.out.println("  Greater than 'Apple': " +
                         strStorage.isGreaterThan("Apple"));

        Storage<Integer> intStorage = new Storage<>();
        intStorage.store(42);
        System.out.println("  Greater than 30: " +
                         intStorage.isGreaterThan(30));

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

        interface Nameable {
            String getName();
        }

        interface Identifiable {
            long getId();
        }

        class Entity<T extends Nameable & Identifiable> {
            private T item;

            public Entity(T item) {
                this.item = item;
            }

            public void display() {
                System.out.println("  ID: " + item.getId() +
                                 ", Name: " + item.getName());
            }
        }

        class User implements Nameable, Identifiable {
            private long id;
            private String name;

            User(long id, String name) {
                this.id = id;
                this.name = name;
            }

            @Override
            public String getName() { return name; }

            @Override
            public long getId() { return id; }
        }

        Entity<User> userEntity = new Entity<>(new User(1, "Alice"));
        userEntity.display();

        System.out.println("\nThree bounds:");

        interface Readable {
            String read();
        }

        interface Writable {
            void write(String data);
        }

        interface Closeable {
            void close();
        }

        class Resource<T extends Readable & Writable & Closeable> {
            private T resource;

            public Resource(T resource) {
                this.resource = resource;
            }

            public void process() {
                String data = resource.read();
                System.out.println("  Read: " + data);
                resource.write("Processed: " + data);
                resource.close();
            }
        }

        class File implements Readable, Writable, Closeable {
            private String content = "File content";

            @Override
            public String read() { return content; }

            @Override
            public void write(String data) {
                System.out.println("  Writing: " + data);
            }

            @Override
            public void close() {
                System.out.println("  Closed");
            }
        }

        Resource<File> fileResource = new Resource<>(new File());
        fileResource.process();
    }
}
import java.io.Serializable;

public class MultipleBounds {
    static class Calculator<T extends Number & Comparable<T>> {
        public T max(T a, T b) {
            return a.compareTo(b) > 0 ? a : b;
        }

        public double add(T a, T b) {
            return a.doubleValue() + b.doubleValue();
        }

        public boolean inRange(T value, T min, T max) {
            return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;
        }
    }

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

        Calculator<Integer> intCalc = new Calculator<>();
        System.out.println("  Max(5, 10): " + intCalc.max(5, 10));
        System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
        int rangeValue = 4;
        System.out.println("  InRange(" + rangeValue + ", 5, 10): " +
                         intCalc.inRange(rangeValue, 5, 10));

        Calculator<Double> doubleCalc = new Calculator<>();
        System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));

        // Multiple bounds: <T extends Type1 & Type2 & Type3>
        // Class bound must come first (can only have one class)
        // Interface bounds follow, separated by &
        // T must satisfy ALL bounds

        System.out.println("\nSerializable + Comparable:");

        class Storage<T extends Serializable & Comparable<T>> {
            private T value;

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

            public T retrieve() {
                return value;
            }

            public boolean isGreaterThan(T other) {
                return value != null && value.compareTo(other) > 0;
            }
        }

        Storage<String> strStorage = new Storage<>();
        strStorage.store("Hello");
        System.out.println("  Greater than 'Apple': " +
                         strStorage.isGreaterThan("Apple"));

        Storage<Integer> intStorage = new Storage<>();
        intStorage.store(42);
        System.out.println("  Greater than 30: " +
                         intStorage.isGreaterThan(30));

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

        interface Nameable {
            String getName();
        }

        interface Identifiable {
            long getId();
        }

        class Entity<T extends Nameable & Identifiable> {
            private T item;

            public Entity(T item) {
                this.item = item;
            }

            public void display() {
                System.out.println("  ID: " + item.getId() +
                                 ", Name: " + item.getName());
            }
        }

        class User implements Nameable, Identifiable {
            private long id;
            private String name;

            User(long id, String name) {
                this.id = id;
                this.name = name;
            }

            @Override
            public String getName() { return name; }

            @Override
            public long getId() { return id; }
        }

        Entity<User> userEntity = new Entity<>(new User(1, "Alice"));
        userEntity.display();

        System.out.println("\nThree bounds:");

        interface Readable {
            String read();
        }

        interface Writable {
            void write(String data);
        }

        interface Closeable {
            void close();
        }

        class Resource<T extends Readable & Writable & Closeable> {
            private T resource;

            public Resource(T resource) {
                this.resource = resource;
            }

            public void process() {
                String data = resource.read();
                System.out.println("  Read: " + data);
                resource.write("Processed: " + data);
                resource.close();
            }
        }

        class File implements Readable, Writable, Closeable {
            private String content = "File content";

            @Override
            public String read() { return content; }

            @Override
            public void write(String data) {
                System.out.println("  Writing: " + data);
            }

            @Override
            public void close() {
                System.out.println("  Closed");
            }
        }

        Resource<File> fileResource = new Resource<>(new File());
        fileResource.process();
    }
}
import java.io.Serializable;

public class MultipleBounds {
    static class Calculator<T extends Number & Comparable<T>> {
        public T max(T a, T b) {
            return a.compareTo(b) > 0 ? a : b;
        }

        public double add(T a, T b) {
            return a.doubleValue() + b.doubleValue();
        }

        public boolean inRange(T value, T min, T max) {
            return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;
        }
    }

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

        Calculator<Integer> intCalc = new Calculator<>();
        System.out.println("  Max(5, 10): " + intCalc.max(5, 10));
        System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
        int rangeValue = 12;
        System.out.println("  InRange(" + rangeValue + ", 5, 10): " +
                         intCalc.inRange(rangeValue, 5, 10));

        Calculator<Double> doubleCalc = new Calculator<>();
        System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));

        // Multiple bounds: <T extends Type1 & Type2 & Type3>
        // Class bound must come first (can only have one class)
        // Interface bounds follow, separated by &
        // T must satisfy ALL bounds

        System.out.println("\nSerializable + Comparable:");

        class Storage<T extends Serializable & Comparable<T>> {
            private T value;

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

            public T retrieve() {
                return value;
            }

            public boolean isGreaterThan(T other) {
                return value != null && value.compareTo(other) > 0;
            }
        }

        Storage<String> strStorage = new Storage<>();
        strStorage.store("Hello");
        System.out.println("  Greater than 'Apple': " +
                         strStorage.isGreaterThan("Apple"));

        Storage<Integer> intStorage = new Storage<>();
        intStorage.store(42);
        System.out.println("  Greater than 30: " +
                         intStorage.isGreaterThan(30));

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

        interface Nameable {
            String getName();
        }

        interface Identifiable {
            long getId();
        }

        class Entity<T extends Nameable & Identifiable> {
            private T item;

            public Entity(T item) {
                this.item = item;
            }

            public void display() {
                System.out.println("  ID: " + item.getId() +
                                 ", Name: " + item.getName());
            }
        }

        class User implements Nameable, Identifiable {
            private long id;
            private String name;

            User(long id, String name) {
                this.id = id;
                this.name = name;
            }

            @Override
            public String getName() { return name; }

            @Override
            public long getId() { return id; }
        }

        Entity<User> userEntity = new Entity<>(new User(1, "Alice"));
        userEntity.display();

        System.out.println("\nThree bounds:");

        interface Readable {
            String read();
        }

        interface Writable {
            void write(String data);
        }

        interface Closeable {
            void close();
        }

        class Resource<T extends Readable & Writable & Closeable> {
            private T resource;

            public Resource(T resource) {
                this.resource = resource;
            }

            public void process() {
                String data = resource.read();
                System.out.println("  Read: " + data);
                resource.write("Processed: " + data);
                resource.close();
            }
        }

        class File implements Readable, Writable, Closeable {
            private String content = "File content";

            @Override
            public String read() { return content; }

            @Override
            public void write(String data) {
                System.out.println("  Writing: " + data);
            }

            @Override
            public void close() {
                System.out.println("  Closed");
            }
        }

        Resource<File> fileResource = new Resource<>(new File());
        fileResource.process();
    }
}
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Multiple bounds:\n");20    21    Calculator<Integer> intCalc = new Calculator<>();22    System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23    System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
    outputMultiple bounds:
    Multiple bounds:
  2. public T max(T a, T b)

    pass 1 of 4
    4static class Calculator<T extends Number & Comparable<T>> {5    public T max(T a5, T b10) {6        return a.compareTo(b10) > 0 ? a5 : b;7    }
    All 4 passes — pass 1 is the card above
    passab
    1510
    2510
    33.142.71
    43.142.71
  3. System.out.println(" Max(5, 10): " + intCalc.max(5, 10));

    21Calculator<Integer> intCalc = new Calculator<>();22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
    output  Max(5, 10): 10
  4. System.out.println(" Max(5, 10): " + intCalc.max(5, 10));

    21Calculator<Integer> intCalc = new Calculator<>();22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 7; //@rangeValue=7, 4, 12
    output  Max(5, 10): 10
  5. public double add(T a, T b)

    pass 1 of 2
    9public double add(T a5, T b10) {10    return a.doubleValue() + b.doubleValue();11}
  6. System.out.println(" Add(5, 10): " + intCalc.add(5, 10));

    22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 7; //@rangeValue=7, 4, 12
    output  Add(5, 10): 15.0
  7. public double add(T a, T b)

    pass 2 of 2
    9public double add(T a5, T b10) {10    return a.doubleValue() + b.doubleValue();11}
  8. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 7; //@rangeValue=7, 4, 1225System.out.println("  InRange(" + rangeValue7 + ", 5, 10): " +26                 intCalc.inRange(rangeValue7, 5, 10));
    output  Add(5, 10): 15.0
  9. public boolean inRange(T value, T min, T max)

    pass 1 of 2
    13public boolean inRange(T value7, T min5, T max10) {14    return value.compareTo(min5) >= 0 && value.compareTo(max10) <= 0;15}
  10. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    24int rangeValue = 7; //@rangeValue=7, 4, 1225System.out.println("  InRange(" + rangeValue7 + ", 5, 10): " +26                 intCalc.inRange(rangeValue7, 5, 10));
    output  InRange(7, 5, 10): true
  11. public boolean inRange(T value, T min, T max)

    pass 2 of 2
    13public boolean inRange(T value7, T min5, T max10) {14    return value.compareTo(min5) >= 0 && value.compareTo(max10) <= 0;15}
  12. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    24int rangeValue = 7; //@rangeValue=7, 4, 1225System.out.println("  InRange(" + rangeValue7 + ", 5, 10): " +26                 intCalc.inRange(rangeValue7, 5, 10));2728Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));
    output  InRange(7, 5, 10): true
  13. System.out.println(" Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71))…

    28Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));
    output  Max(3.14, 2.71): 3.14
  14. System.out.println(" Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71))…

    28Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));3031// Multiple bounds: <T extends Type1 & Type2 & Type3>32// Class bound must come first (can only have one class)33// Interface bounds follow, separated by &34// T must satisfy ALL bounds3536System.out.println("\nSerializable + Comparable:");3738class Storage<T extends Serializable & Comparable<T>> {39    private T value;40    41    public void store(T value) {42        this.value = value;43        System.out.println("  Stored (serializable): " + value);44    }45    46    public T retrieve() {47        return value;48    }49    50    public boolean isGreaterThan(T other) {51        return value != null && value.compareTo(other) > 0;52    }53}5455Storage<String> strStorage = new Storage<>();56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 
    output  Max(3.14, 2.71): 3.14
    
    Serializable + Comparable:
    
    Serializable + Comparable:
  15. this.value ← Hello

    pass 1 of 2
    41public void store(T valueHello) {42    this.value→ Hello = valueHello;43    System.out.println("  Stored (serializable): " + valueHello);44}
    output  Stored (serializable): Hello
  16. strStorage.store("Hello");

    55Storage<String> strStorage = new Storage<>();56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 58                 strStorage.isGreaterThan("Apple"));
  17. public boolean isGreaterThan(T other)

    pass 1 of 2
    50public boolean isGreaterThan(T otherApple) {51    return valueHello != null && value.compareTo(otherApple) > 0;52}
  18. intStorage ← ⟨MultipleBounds$1Storage A⟩

    56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 58                 strStorage.isGreaterThan("Apple"));5960Storage<Integer> intStorage→ ⟨MultipleBounds$1Storage A⟩ = new Storage<>();61intStorage.store(42);62System.out.println("  Greater than 30: " + 
    output  Greater than 'Apple': true
  19. this.value ← 42

    pass 2 of 2
    41public void store(T value42) {42    this.value→ 42 = value42;43    System.out.println("  Stored (serializable): " + value42);44}
    output  Stored (serializable): 42
  20. intStorage.store(42);

    60Storage<Integer> intStorage = new Storage<>();61intStorage.store(42);62System.out.println("  Greater than 30: " + 63                 intStorage.isGreaterThan(30));
  21. public boolean isGreaterThan(T other)

    pass 2 of 2
    50public boolean isGreaterThan(T other30) {51    return value42 != null && value.compareTo(other30) > 0;52}
  22. System.out.println(" Greater than 30: " +

    61intStorage.store(42);62System.out.println("  Greater than 30: " + 63                 intStorage.isGreaterThan(30));6465System.out.println("\nCustom interfaces:");
    output  Greater than 30: true
    
    Custom interfaces:
  23. this.id ← 1, this.name ← Alice

    92User(long id1, String nameAlice) {93    this.id→ 1 = id1;94    this.name→ Alice = nameAlice;95}
  24. this.item ← ⟨MultipleBounds$1User B⟩

    78public Entity(T item⟨MultipleBounds$1User B⟩) {79    this.item→ ⟨MultipleBounds$1User B⟩ = item⟨MultipleBounds$1User B⟩;80}
  25. userEntity.display();

    104Entity<User> userEntity = new Entity<>(new User(1, "Alice"));105userEntity.display();
  26. @Override public long getId()

    100    @Override101    public long getId() { return id1; }102}
  27. @Override public String getName()

    97@Override98public String getName() { return nameAlice; }
  28. System.out.println(" ID: " + item.getId() +

    82    public void display() {83        System.out.println("  ID: " + item.getId() + 84                         ", Name: " + item.getName());85    }86}8788class User implements Nameable, Identifiable {89    private long id;90    private String name;91    92    User(long id, String name) {93        this.id = id;94        this.name = name;95    }96    97    @Override98    public String getName() { return name; }99    100    @Override101    public long getId() { return id; }102}103104Entity<User> userEntity = new Entity<>(new User(1, "Alice"));105userEntity.display();106107System.out.println("\nThree bounds:");
    output  ID: 1, Name: Alice
    
    Three bounds:
  29. this.resource ← ⟨MultipleBounds$1File C⟩

    124public Resource(T resource⟨MultipleBounds$1File C⟩) {125    this.resource→ ⟨MultipleBounds$1File C⟩ = resource⟨MultipleBounds$1File C⟩;126}
  30. fileResource.process();

    153    Resource<File> fileResource = new Resource<>(new File());154    fileResource.process();155}
  31. @Override public String read()

    139@Override140public String read() { return contentFile content; }
  32. data ← File content

    128public void process() {129    String data→ File content = resource.read();130    System.out.println("  Read: " + dataFile content);131    resource.write("Processed: " + dataFile content);132    resource.close();
    output  Read: File content
  33. @Override public void write(String data)

    130        System.out.println("  Read: " + data);131        resource.write("Processed: " + dataFile content);132        resource.close();133    }134}135136class File implements Readable, Writable, Closeable {137    private String content = "File content";138    139    @Override140    public String read() { return content; }141    142    @Override143    public void write(String dataProcessed: File content) { 144        System.out.println("  Writing: " + dataProcessed: File content);145    }
    output  Writing: Processed: File content
  34. @Override public void close()

    131        resource.write("Processed: " + data);132        resource.close();133    }134}135136class File implements Readable, Writable, Closeable {137    private String content = "File content";138    139    @Override140    public String read() { return content; }141    142    @Override143    public void write(String data) { 144        System.out.println("  Writing: " + data);145    }146    147    @Override148    public void close() { 149        System.out.println("  Closed");150    }
    output  Closed
  35. fileResource.process();

    153    Resource<File> fileResource = new Resource<>(new File());154    fileResource.process();155}
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Multiple bounds:\n");20    21    Calculator<Integer> intCalc = new Calculator<>();22    System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23    System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
    outputMultiple bounds:
    Multiple bounds:
  2. public T max(T a, T b)

    pass 1 of 4
    4static class Calculator<T extends Number & Comparable<T>> {5    public T max(T a5, T b10) {6        return a.compareTo(b10) > 0 ? a5 : b;7    }
    All 4 passes — pass 1 is the card above
    passab
    1510
    2510
    33.142.71
    43.142.71
  3. System.out.println(" Max(5, 10): " + intCalc.max(5, 10));

    21Calculator<Integer> intCalc = new Calculator<>();22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
    output  Max(5, 10): 10
  4. System.out.println(" Max(5, 10): " + intCalc.max(5, 10));

    21Calculator<Integer> intCalc = new Calculator<>();22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 4;
    output  Max(5, 10): 10
  5. public double add(T a, T b)

    pass 1 of 2
    9public double add(T a5, T b10) {10    return a.doubleValue() + b.doubleValue();11}
  6. System.out.println(" Add(5, 10): " + intCalc.add(5, 10));

    22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 4;
    output  Add(5, 10): 15.0
  7. public double add(T a, T b)

    pass 2 of 2
    9public double add(T a5, T b10) {10    return a.doubleValue() + b.doubleValue();11}
  8. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 4;25System.out.println("  InRange(" + rangeValue4 + ", 5, 10): " +26                 intCalc.inRange(rangeValue4, 5, 10));
    output  Add(5, 10): 15.0
  9. public boolean inRange(T value, T min, T max)

    pass 1 of 2
    13public boolean inRange(T value4, T min5, T max10) {14    return value.compareTo(min5) >= 0 && value.compareTo(max10) <= 0;15}
  10. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    24int rangeValue = 4;25System.out.println("  InRange(" + rangeValue4 + ", 5, 10): " +26                 intCalc.inRange(rangeValue4, 5, 10));
    output  InRange(4, 5, 10): false
  11. public boolean inRange(T value, T min, T max)

    pass 2 of 2
    13public boolean inRange(T value4, T min5, T max10) {14    return value.compareTo(min5) >= 0 && value.compareTo(max10) <= 0;15}
  12. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    24int rangeValue = 4;25System.out.println("  InRange(" + rangeValue4 + ", 5, 10): " +26                 intCalc.inRange(rangeValue4, 5, 10));2728Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));
    output  InRange(4, 5, 10): false
  13. System.out.println(" Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71))…

    28Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));
    output  Max(3.14, 2.71): 3.14
  14. System.out.println(" Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71))…

    28Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));3031// Multiple bounds: <T extends Type1 & Type2 & Type3>32// Class bound must come first (can only have one class)33// Interface bounds follow, separated by &34// T must satisfy ALL bounds3536System.out.println("\nSerializable + Comparable:");3738class Storage<T extends Serializable & Comparable<T>> {39    private T value;40    41    public void store(T value) {42        this.value = value;43        System.out.println("  Stored (serializable): " + value);44    }45    46    public T retrieve() {47        return value;48    }49    50    public boolean isGreaterThan(T other) {51        return value != null && value.compareTo(other) > 0;52    }53}5455Storage<String> strStorage = new Storage<>();56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 
    output  Max(3.14, 2.71): 3.14
    
    Serializable + Comparable:
    
    Serializable + Comparable:
  15. this.value ← Hello

    pass 1 of 2
    41public void store(T valueHello) {42    this.value→ Hello = valueHello;43    System.out.println("  Stored (serializable): " + valueHello);44}
    output  Stored (serializable): Hello
  16. strStorage.store("Hello");

    55Storage<String> strStorage = new Storage<>();56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 58                 strStorage.isGreaterThan("Apple"));
  17. public boolean isGreaterThan(T other)

    pass 1 of 2
    50public boolean isGreaterThan(T otherApple) {51    return valueHello != null && value.compareTo(otherApple) > 0;52}
  18. intStorage ← ⟨MultipleBounds$1Storage A⟩

    56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 58                 strStorage.isGreaterThan("Apple"));5960Storage<Integer> intStorage→ ⟨MultipleBounds$1Storage A⟩ = new Storage<>();61intStorage.store(42);62System.out.println("  Greater than 30: " + 
    output  Greater than 'Apple': true
  19. this.value ← 42

    pass 2 of 2
    41public void store(T value42) {42    this.value→ 42 = value42;43    System.out.println("  Stored (serializable): " + value42);44}
    output  Stored (serializable): 42
  20. intStorage.store(42);

    60Storage<Integer> intStorage = new Storage<>();61intStorage.store(42);62System.out.println("  Greater than 30: " + 63                 intStorage.isGreaterThan(30));
  21. public boolean isGreaterThan(T other)

    pass 2 of 2
    50public boolean isGreaterThan(T other30) {51    return value42 != null && value.compareTo(other30) > 0;52}
  22. System.out.println(" Greater than 30: " +

    61intStorage.store(42);62System.out.println("  Greater than 30: " + 63                 intStorage.isGreaterThan(30));6465System.out.println("\nCustom interfaces:");
    output  Greater than 30: true
    
    Custom interfaces:
  23. this.id ← 1, this.name ← Alice

    92User(long id1, String nameAlice) {93    this.id→ 1 = id1;94    this.name→ Alice = nameAlice;95}
  24. this.item ← ⟨MultipleBounds$1User B⟩

    78public Entity(T item⟨MultipleBounds$1User B⟩) {79    this.item→ ⟨MultipleBounds$1User B⟩ = item⟨MultipleBounds$1User B⟩;80}
  25. userEntity.display();

    104Entity<User> userEntity = new Entity<>(new User(1, "Alice"));105userEntity.display();
  26. @Override public long getId()

    100    @Override101    public long getId() { return id1; }102}
  27. @Override public String getName()

    97@Override98public String getName() { return nameAlice; }
  28. System.out.println(" ID: " + item.getId() +

    82    public void display() {83        System.out.println("  ID: " + item.getId() + 84                         ", Name: " + item.getName());85    }86}8788class User implements Nameable, Identifiable {89    private long id;90    private String name;91    92    User(long id, String name) {93        this.id = id;94        this.name = name;95    }96    97    @Override98    public String getName() { return name; }99    100    @Override101    public long getId() { return id; }102}103104Entity<User> userEntity = new Entity<>(new User(1, "Alice"));105userEntity.display();106107System.out.println("\nThree bounds:");
    output  ID: 1, Name: Alice
    
    Three bounds:
  29. this.resource ← ⟨MultipleBounds$1File C⟩

    124public Resource(T resource⟨MultipleBounds$1File C⟩) {125    this.resource→ ⟨MultipleBounds$1File C⟩ = resource⟨MultipleBounds$1File C⟩;126}
  30. fileResource.process();

    153    Resource<File> fileResource = new Resource<>(new File());154    fileResource.process();155}
  31. @Override public String read()

    139@Override140public String read() { return contentFile content; }
  32. data ← File content

    128public void process() {129    String data→ File content = resource.read();130    System.out.println("  Read: " + dataFile content);131    resource.write("Processed: " + dataFile content);132    resource.close();
    output  Read: File content
  33. @Override public void write(String data)

    130        System.out.println("  Read: " + data);131        resource.write("Processed: " + dataFile content);132        resource.close();133    }134}135136class File implements Readable, Writable, Closeable {137    private String content = "File content";138    139    @Override140    public String read() { return content; }141    142    @Override143    public void write(String dataProcessed: File content) { 144        System.out.println("  Writing: " + dataProcessed: File content);145    }
    output  Writing: Processed: File content
  34. @Override public void close()

    131        resource.write("Processed: " + data);132        resource.close();133    }134}135136class File implements Readable, Writable, Closeable {137    private String content = "File content";138    139    @Override140    public String read() { return content; }141    142    @Override143    public void write(String data) { 144        System.out.println("  Writing: " + data);145    }146    147    @Override148    public void close() { 149        System.out.println("  Closed");150    }
    output  Closed
  35. fileResource.process();

    153    Resource<File> fileResource = new Resource<>(new File());154    fileResource.process();155}
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Multiple bounds:\n");20    21    Calculator<Integer> intCalc = new Calculator<>();22    System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23    System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
    outputMultiple bounds:
    Multiple bounds:
  2. public T max(T a, T b)

    pass 1 of 4
    4static class Calculator<T extends Number & Comparable<T>> {5    public T max(T a5, T b10) {6        return a.compareTo(b10) > 0 ? a5 : b;7    }
    All 4 passes — pass 1 is the card above
    passab
    1510
    2510
    33.142.71
    43.142.71
  3. System.out.println(" Max(5, 10): " + intCalc.max(5, 10));

    21Calculator<Integer> intCalc = new Calculator<>();22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));
    output  Max(5, 10): 10
  4. System.out.println(" Max(5, 10): " + intCalc.max(5, 10));

    21Calculator<Integer> intCalc = new Calculator<>();22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 12;
    output  Max(5, 10): 10
  5. public double add(T a, T b)

    pass 1 of 2
    9public double add(T a5, T b10) {10    return a.doubleValue() + b.doubleValue();11}
  6. System.out.println(" Add(5, 10): " + intCalc.add(5, 10));

    22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 12;
    output  Add(5, 10): 15.0
  7. public double add(T a, T b)

    pass 2 of 2
    9public double add(T a5, T b10) {10    return a.doubleValue() + b.doubleValue();11}
  8. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    22System.out.println("  Max(5, 10): " + intCalc.max(5, 10));23System.out.println("  Add(5, 10): " + intCalc.add(5, 10));24int rangeValue = 12;25System.out.println("  InRange(" + rangeValue12 + ", 5, 10): " +26                 intCalc.inRange(rangeValue12, 5, 10));
    output  Add(5, 10): 15.0
  9. public boolean inRange(T value, T min, T max)

    pass 1 of 2
    13public boolean inRange(T value12, T min5, T max10) {14    return value.compareTo(min5) >= 0 && value.compareTo(max10) <= 0;15}
  10. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    24int rangeValue = 12;25System.out.println("  InRange(" + rangeValue12 + ", 5, 10): " +26                 intCalc.inRange(rangeValue12, 5, 10));
    output  InRange(12, 5, 10): false
  11. public boolean inRange(T value, T min, T max)

    pass 2 of 2
    13public boolean inRange(T value12, T min5, T max10) {14    return value.compareTo(min5) >= 0 && value.compareTo(max10) <= 0;15}
  12. System.out.println(" InRange(" + rangeValue + ", 5, 10): " +

    24int rangeValue = 12;25System.out.println("  InRange(" + rangeValue12 + ", 5, 10): " +26                 intCalc.inRange(rangeValue12, 5, 10));2728Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));
    output  InRange(12, 5, 10): false
  13. System.out.println(" Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71))…

    28Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));
    output  Max(3.14, 2.71): 3.14
  14. System.out.println(" Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71))…

    28Calculator<Double> doubleCalc = new Calculator<>();29System.out.println("  Max(3.14, 2.71): " + doubleCalc.max(3.14, 2.71));3031// Multiple bounds: <T extends Type1 & Type2 & Type3>32// Class bound must come first (can only have one class)33// Interface bounds follow, separated by &34// T must satisfy ALL bounds3536System.out.println("\nSerializable + Comparable:");3738class Storage<T extends Serializable & Comparable<T>> {39    private T value;40    41    public void store(T value) {42        this.value = value;43        System.out.println("  Stored (serializable): " + value);44    }45    46    public T retrieve() {47        return value;48    }49    50    public boolean isGreaterThan(T other) {51        return value != null && value.compareTo(other) > 0;52    }53}5455Storage<String> strStorage = new Storage<>();56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 
    output  Max(3.14, 2.71): 3.14
    
    Serializable + Comparable:
    
    Serializable + Comparable:
  15. this.value ← Hello

    pass 1 of 2
    41public void store(T valueHello) {42    this.value→ Hello = valueHello;43    System.out.println("  Stored (serializable): " + valueHello);44}
    output  Stored (serializable): Hello
  16. strStorage.store("Hello");

    55Storage<String> strStorage = new Storage<>();56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 58                 strStorage.isGreaterThan("Apple"));
  17. public boolean isGreaterThan(T other)

    pass 1 of 2
    50public boolean isGreaterThan(T otherApple) {51    return valueHello != null && value.compareTo(otherApple) > 0;52}
  18. intStorage ← ⟨MultipleBounds$1Storage A⟩

    56strStorage.store("Hello");57System.out.println("  Greater than 'Apple': " + 58                 strStorage.isGreaterThan("Apple"));5960Storage<Integer> intStorage→ ⟨MultipleBounds$1Storage A⟩ = new Storage<>();61intStorage.store(42);62System.out.println("  Greater than 30: " + 
    output  Greater than 'Apple': true
  19. this.value ← 42

    pass 2 of 2
    41public void store(T value42) {42    this.value→ 42 = value42;43    System.out.println("  Stored (serializable): " + value42);44}
    output  Stored (serializable): 42
  20. intStorage.store(42);

    60Storage<Integer> intStorage = new Storage<>();61intStorage.store(42);62System.out.println("  Greater than 30: " + 63                 intStorage.isGreaterThan(30));
  21. public boolean isGreaterThan(T other)

    pass 2 of 2
    50public boolean isGreaterThan(T other30) {51    return value42 != null && value.compareTo(other30) > 0;52}
  22. System.out.println(" Greater than 30: " +

    61intStorage.store(42);62System.out.println("  Greater than 30: " + 63                 intStorage.isGreaterThan(30));6465System.out.println("\nCustom interfaces:");
    output  Greater than 30: true
    
    Custom interfaces:
  23. this.id ← 1, this.name ← Alice

    92User(long id1, String nameAlice) {93    this.id→ 1 = id1;94    this.name→ Alice = nameAlice;95}
  24. this.item ← ⟨MultipleBounds$1User B⟩

    78public Entity(T item⟨MultipleBounds$1User B⟩) {79    this.item→ ⟨MultipleBounds$1User B⟩ = item⟨MultipleBounds$1User B⟩;80}
  25. userEntity.display();

    104Entity<User> userEntity = new Entity<>(new User(1, "Alice"));105userEntity.display();
  26. @Override public long getId()

    100    @Override101    public long getId() { return id1; }102}
  27. @Override public String getName()

    97@Override98public String getName() { return nameAlice; }
  28. System.out.println(" ID: " + item.getId() +

    82    public void display() {83        System.out.println("  ID: " + item.getId() + 84                         ", Name: " + item.getName());85    }86}8788class User implements Nameable, Identifiable {89    private long id;90    private String name;91    92    User(long id, String name) {93        this.id = id;94        this.name = name;95    }96    97    @Override98    public String getName() { return name; }99    100    @Override101    public long getId() { return id; }102}103104Entity<User> userEntity = new Entity<>(new User(1, "Alice"));105userEntity.display();106107System.out.println("\nThree bounds:");
    output  ID: 1, Name: Alice
    
    Three bounds:
  29. this.resource ← ⟨MultipleBounds$1File C⟩

    124public Resource(T resource⟨MultipleBounds$1File C⟩) {125    this.resource→ ⟨MultipleBounds$1File C⟩ = resource⟨MultipleBounds$1File C⟩;126}
  30. fileResource.process();

    153    Resource<File> fileResource = new Resource<>(new File());154    fileResource.process();155}
  31. @Override public String read()

    139@Override140public String read() { return contentFile content; }
  32. data ← File content

    128public void process() {129    String data→ File content = resource.read();130    System.out.println("  Read: " + dataFile content);131    resource.write("Processed: " + dataFile content);132    resource.close();
    output  Read: File content
  33. @Override public void write(String data)

    130        System.out.println("  Read: " + data);131        resource.write("Processed: " + dataFile content);132        resource.close();133    }134}135136class File implements Readable, Writable, Closeable {137    private String content = "File content";138    139    @Override140    public String read() { return content; }141    142    @Override143    public void write(String dataProcessed: File content) { 144        System.out.println("  Writing: " + dataProcessed: File content);145    }
    output  Writing: Processed: File content
  34. @Override public void close()

    131        resource.write("Processed: " + data);132        resource.close();133    }134}135136class File implements Readable, Writable, Closeable {137    private String content = "File content";138    139    @Override140    public String read() { return content; }141    142    @Override143    public void write(String data) { 144        System.out.println("  Writing: " + data);145    }146    147    @Override148    public void close() { 149        System.out.println("  Closed");150    }
    output  Closed
  35. fileResource.process();

    153    Resource<File> fileResource = new Resource<>(new File());154    fileResource.process();155}

<T extends Number & Comparable<T>> - class first, then interfaces with &.

Bounded methods

Apply bounds to method-level type parameters.

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

public class BoundedMethods {
    public static <T extends Comparable<T>> T findMax(List<T> list) {
        if (list.isEmpty()) {
            return null;
        }

        T max = list.get(0);
        for (T item : list) {
            if (item.compareTo(max) > 0) {
                max = item;
            }
        }
        return max;
    }

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

        List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 7);
        Integer maxNum = findMax(numbers);
        System.out.println("  Max number: " + maxNum);

        List<String> words = Arrays.asList("apple", "zebra", "banana");
        String maxWord = findMax(words);
        System.out.println("  Max word: " + maxWord);

        // Method can declare its own type parameters with bounds
        // <T extends Type> before return type
        // Bound applies only to that method
        // Enables calling bounded type's methods

        System.out.println("\nNumeric operations:");

        class MathUtils {
            public static <T extends Number> double sum(List<T> numbers) {
                double total = 0;
                for (T num : numbers) {
                    total += num.doubleValue();
                }
                return total;
            }

            public static <T extends Number> double average(List<T> numbers) {
                return sum(numbers) / numbers.size();
            }
        }

        List<Integer> intList = Arrays.asList(10, 20, 30);
        System.out.println("  Sum: " + MathUtils.sum(intList));
        System.out.println("  Average: " + MathUtils.average(intList));

        List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);
        System.out.println("  Sum: " + MathUtils.sum(doubleList));

        System.out.println("\nCount matching:");

        class Counter {
            public static <T> int countMatching(List<T> list, T target) {
                int count = 0;
                for (T item : list) {
                    if (item.equals(target)) {
                        count++;
                    }
                }
                return count;
            }

            public static <T extends Comparable<T>> int countGreater(
                    List<T> list, T threshold) {
                int count = 0;
                for (T item : list) {
                    if (item.compareTo(threshold) > 0) {
                        count++;
                    }
                }
                return count;
            }
        }

        List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);
        System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));
        System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));

        System.out.println("\nCopy method:");

        class Copier {
            public static <T> void copy(List<T> source, List<T> dest) {
                dest.clear();
                dest.addAll(source);
            }

            public static <T extends Comparable<T>> void copyGreater(
                    List<T> source, List<T> dest, T threshold) {
                dest.clear();
                for (T item : source) {
                    if (item.compareTo(threshold) > 0) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> src = Arrays.asList(1, 5, 3, 8, 2, 9);
        List<Integer> dst = new ArrayList<>();

        int threshold = 4;
        Copier.copyGreater(src, dst, threshold);
        System.out.println("  Copied > " + threshold + ": " + dst);

        System.out.println("\nMin/Max finder:");

        class MinMax {
            public static <T extends Comparable<T>> T min(T a, T b) {
                return a.compareTo(b) < 0 ? a : b;
            }

            public static <T extends Comparable<T>> T max(T a, T b) {
                return a.compareTo(b) > 0 ? a : b;
            }

            public static <T extends Comparable<T>> T clamp(
                    T value, T min, T max) {
                if (value.compareTo(min) < 0) return min;
                if (value.compareTo(max) > 0) return max;
                return value;
            }
        }

        System.out.println("  min(5, 10): " + MinMax.min(5, 10));
        System.out.println("  max(5, 10): " + MinMax.max(5, 10));
        System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));
        System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));
    }
}
import java.util.*;

public class BoundedMethods {
    public static <T extends Comparable<T>> T findMax(List<T> list) {
        if (list.isEmpty()) {
            return null;
        }

        T max = list.get(0);
        for (T item : list) {
            if (item.compareTo(max) > 0) {
                max = item;
            }
        }
        return max;
    }

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

        List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 7);
        Integer maxNum = findMax(numbers);
        System.out.println("  Max number: " + maxNum);

        List<String> words = Arrays.asList("apple", "zebra", "banana");
        String maxWord = findMax(words);
        System.out.println("  Max word: " + maxWord);

        // Method can declare its own type parameters with bounds
        // <T extends Type> before return type
        // Bound applies only to that method
        // Enables calling bounded type's methods

        System.out.println("\nNumeric operations:");

        class MathUtils {
            public static <T extends Number> double sum(List<T> numbers) {
                double total = 0;
                for (T num : numbers) {
                    total += num.doubleValue();
                }
                return total;
            }

            public static <T extends Number> double average(List<T> numbers) {
                return sum(numbers) / numbers.size();
            }
        }

        List<Integer> intList = Arrays.asList(10, 20, 30);
        System.out.println("  Sum: " + MathUtils.sum(intList));
        System.out.println("  Average: " + MathUtils.average(intList));

        List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);
        System.out.println("  Sum: " + MathUtils.sum(doubleList));

        System.out.println("\nCount matching:");

        class Counter {
            public static <T> int countMatching(List<T> list, T target) {
                int count = 0;
                for (T item : list) {
                    if (item.equals(target)) {
                        count++;
                    }
                }
                return count;
            }

            public static <T extends Comparable<T>> int countGreater(
                    List<T> list, T threshold) {
                int count = 0;
                for (T item : list) {
                    if (item.compareTo(threshold) > 0) {
                        count++;
                    }
                }
                return count;
            }
        }

        List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);
        System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));
        System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));

        System.out.println("\nCopy method:");

        class Copier {
            public static <T> void copy(List<T> source, List<T> dest) {
                dest.clear();
                dest.addAll(source);
            }

            public static <T extends Comparable<T>> void copyGreater(
                    List<T> source, List<T> dest, T threshold) {
                dest.clear();
                for (T item : source) {
                    if (item.compareTo(threshold) > 0) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> src = Arrays.asList(1, 5, 3, 8, 2, 9);
        List<Integer> dst = new ArrayList<>();

        int threshold = 6;
        Copier.copyGreater(src, dst, threshold);
        System.out.println("  Copied > " + threshold + ": " + dst);

        System.out.println("\nMin/Max finder:");

        class MinMax {
            public static <T extends Comparable<T>> T min(T a, T b) {
                return a.compareTo(b) < 0 ? a : b;
            }

            public static <T extends Comparable<T>> T max(T a, T b) {
                return a.compareTo(b) > 0 ? a : b;
            }

            public static <T extends Comparable<T>> T clamp(
                    T value, T min, T max) {
                if (value.compareTo(min) < 0) return min;
                if (value.compareTo(max) > 0) return max;
                return value;
            }
        }

        System.out.println("  min(5, 10): " + MinMax.min(5, 10));
        System.out.println("  max(5, 10): " + MinMax.max(5, 10));
        System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));
        System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));
    }
}
import java.util.*;

public class BoundedMethods {
    public static <T extends Comparable<T>> T findMax(List<T> list) {
        if (list.isEmpty()) {
            return null;
        }

        T max = list.get(0);
        for (T item : list) {
            if (item.compareTo(max) > 0) {
                max = item;
            }
        }
        return max;
    }

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

        List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 7);
        Integer maxNum = findMax(numbers);
        System.out.println("  Max number: " + maxNum);

        List<String> words = Arrays.asList("apple", "zebra", "banana");
        String maxWord = findMax(words);
        System.out.println("  Max word: " + maxWord);

        // Method can declare its own type parameters with bounds
        // <T extends Type> before return type
        // Bound applies only to that method
        // Enables calling bounded type's methods

        System.out.println("\nNumeric operations:");

        class MathUtils {
            public static <T extends Number> double sum(List<T> numbers) {
                double total = 0;
                for (T num : numbers) {
                    total += num.doubleValue();
                }
                return total;
            }

            public static <T extends Number> double average(List<T> numbers) {
                return sum(numbers) / numbers.size();
            }
        }

        List<Integer> intList = Arrays.asList(10, 20, 30);
        System.out.println("  Sum: " + MathUtils.sum(intList));
        System.out.println("  Average: " + MathUtils.average(intList));

        List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);
        System.out.println("  Sum: " + MathUtils.sum(doubleList));

        System.out.println("\nCount matching:");

        class Counter {
            public static <T> int countMatching(List<T> list, T target) {
                int count = 0;
                for (T item : list) {
                    if (item.equals(target)) {
                        count++;
                    }
                }
                return count;
            }

            public static <T extends Comparable<T>> int countGreater(
                    List<T> list, T threshold) {
                int count = 0;
                for (T item : list) {
                    if (item.compareTo(threshold) > 0) {
                        count++;
                    }
                }
                return count;
            }
        }

        List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);
        System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));
        System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));

        System.out.println("\nCopy method:");

        class Copier {
            public static <T> void copy(List<T> source, List<T> dest) {
                dest.clear();
                dest.addAll(source);
            }

            public static <T extends Comparable<T>> void copyGreater(
                    List<T> source, List<T> dest, T threshold) {
                dest.clear();
                for (T item : source) {
                    if (item.compareTo(threshold) > 0) {
                        dest.add(item);
                    }
                }
            }
        }

        List<Integer> src = Arrays.asList(1, 5, 3, 8, 2, 9);
        List<Integer> dst = new ArrayList<>();

        int threshold = 8;
        Copier.copyGreater(src, dst, threshold);
        System.out.println("  Copied > " + threshold + ": " + dst);

        System.out.println("\nMin/Max finder:");

        class MinMax {
            public static <T extends Comparable<T>> T min(T a, T b) {
                return a.compareTo(b) < 0 ? a : b;
            }

            public static <T extends Comparable<T>> T max(T a, T b) {
                return a.compareTo(b) > 0 ? a : b;
            }

            public static <T extends Comparable<T>> T clamp(
                    T value, T min, T max) {
                if (value.compareTo(min) < 0) return min;
                if (value.compareTo(max) > 0) return max;
                return value;
            }
        }

        System.out.println("  min(5, 10): " + MinMax.min(5, 10));
        System.out.println("  max(5, 10): " + MinMax.max(5, 10));
        System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));
        System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));
    }
}
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Bounded methods:\n");
    outputBounded methods:
    Bounded methods:
  2. max ← 5

    pass 1 of 2
    3public class BoundedMethods {4    public static <T extends Comparable<T>> T findMax(List<T> list[5, 2, 9, 1, 7]) {5        if (list.isEmpty()) {6            return null;7        }8        9        T max→ 5 = list.get(0);10        for (T item : list) {
  3. for (T item : list)

    pass 1 of 8
    9T max = list.get(0);10for (T item5 : list[5, 2, 9, 1, 7]) {11    if (item.compareTo(max) > 0) {
    All 8 passes — pass 1 is the card above
    passitemlistmax
    15[5, 2, 9, 1, 7]
    22[5, 2, 9, 1, 7]
    39[5, 2, 9, 1, 7]5 9
    41[5, 2, 9, 1, 7]
    57[5, 2, 9, 1, 7]
    6apple[apple, zebra, banana]
    7zebra[apple, zebra, banana]apple zebra
    8banana[apple, zebra, banana]
  4. max ← 9

    pass 1 of 2
    10for (T item : list) {11    if (item.compareTo(max5) > 0) {12        max→ 9 = item9;13    }
  5. return max;

    14    }15    return max9;16}
  6. System.out.println(" Max number: " + maxNum);

    22Integer maxNum = findMax(numbers);23System.out.println("  Max number: " + maxNum9);
    output  Max number: 9
      Max number: 9
  7. max ← apple

    pass 2 of 2
    3public class BoundedMethods {4    public static <T extends Comparable<T>> T findMax(List<T> list[apple, zebra, banana]) {5        if (list.isEmpty()) {6            return null;7        }8        9        T max→ apple = list.get(0);10        for (T item : list) {
  8. max ← zebra

    pass 2 of 2
    10for (T item : list) {11    if (item.compareTo(maxapple) > 0) {12        max→ zebra = itemzebra;13    }
  9. return max;

    14    }15    return maxzebra;16}
  10. System.out.println(" Max word: " + maxWord);

    26String maxWord = findMax(words);27System.out.println("  Max word: " + maxWordzebra);2829// Method can declare its own type parameters with bounds30// <T extends Type> before return type31// Bound applies only to that method32// Enables calling bounded type's methods3334System.out.println("\nNumeric operations:");3536class MathUtils {37    public static <T extends Number> double sum(List<T> numbers) {38        double total = 0;39        for (T num : numbers) {40            total += num.doubleValue();41        }42        return total;43    }44    45    public static <T extends Number> double average(List<T> numbers) {46        return sum(numbers) / numbers.size();47    }48}4950List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList));
    output  Max word: zebra
      Max word: zebra
    
    Numeric operations:
    
    Numeric operations:
  11. total ← 0.0

    pass 1 of 6
    36class MathUtils {37    public static <T extends Number> double sum(List<T> numbers[10, 20, 30]) {38        double total→ 0.0 = 0;39        for (T num : numbers) {
    All 6 passes — pass 1 is the card above
    passnumberstotal
    1[10, 20, 30]0.0
    2[10, 20, 30]0.0
    3[10, 20, 30]0.0
    4[10, 20, 30]0.0
    5[1.5, 2.5, 3.5]0.0
    6[1.5, 2.5, 3.5]0.0
  12. total ← 10.0

    pass 1 of 18
    38double total = 0;39for (T num10 : numbers[10, 20, 30]) {40    total→ 10.0 += num.doubleValue();41}
    18 passes — pass 1 is the card above
    passnumnumberstotal
    110[10, 20, 30]0.0 10.0
    220[10, 20, 30]10.0 30.0
    330[10, 20, 30]30.0 60.0
    410[10, 20, 30]0.0 10.0
    520[10, 20, 30]10.0 30.0
    630[10, 20, 30]30.0 60.0
    710[10, 20, 30]0.0 10.0
    820[10, 20, 30]10.0 30.0
    930[10, 20, 30]30.0 60.0
    ⋯ 7 more passes ⋯
    172.5[1.5, 2.5, 3.5]1.5 4.0
    183.5[1.5, 2.5, 3.5]4.0 7.5
  13. return total;

    41    }42    return total60.0;43}
  14. System.out.println(" Sum: " + MathUtils.sum(intList));

    50List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList));
    output  Sum: 60.0
  15. return total;

    41    }42    return total60.0;43}
  16. System.out.println(" Sum: " + MathUtils.sum(intList));

    50List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));
    output  Sum: 60.0
  17. public static <T extends Number> double average(List<T> numbers)

    pass 1 of 2
    45public static <T extends Number> double average(List<T> numbers[10, 20, 30]) {46    return sum(numbers[10, 20, 30]) / numbers.size();47}
  18. return total;

    41    }42    return total60.0;43}
  19. System.out.println(" Average: " + MathUtils.average(intList));

    51System.out.println("  Sum: " + MathUtils.sum(intList));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));
    output  Average: 20.0
  20. public static <T extends Number> double average(List<T> numbers)

    pass 2 of 2
    45public static <T extends Number> double average(List<T> numbers[10, 20, 30]) {46    return sum(numbers[10, 20, 30]) / numbers.size();47}
  21. return total;

    41    }42    return total60.0;43}
  22. System.out.println(" Average: " + MathUtils.average(intList));

    51System.out.println("  Sum: " + MathUtils.sum(intList));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));5354List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));
    output  Average: 20.0
  23. return total;

    41    }42    return total7.5;43}
  24. System.out.println(" Sum: " + MathUtils.sum(doubleList));

    54List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));
    output  Sum: 7.5
  25. return total;

    41    }42    return total7.5;43}
  26. System.out.println(" Sum: " + MathUtils.sum(doubleList));

    54List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));5657System.out.println("\nCount matching:");5859class Counter {60    public static <T> int countMatching(List<T> list, T target) {61        int count = 0;62        for (T item : list) {63            if (item.equals(target)) {64                count++;65            }66        }67        return count;68    }69    70    public static <T extends Comparable<T>> int countGreater(71            List<T> list, T threshold) {72        int count = 0;73        for (T item : list) {74            if (item.compareTo(threshold) > 0) {75                count++;76            }77        }78        return count;79    }80}8182List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));
    output  Sum: 7.5
    
    Count matching:
    
    Count matching:
  27. count ← 0

    pass 1 of 2
    59class Counter {60    public static <T> int countMatching(List<T> list[5, 10, 3, 10, 7], T target10) {61        int count→ 0 = 0;62        for (T item : list) {
  28. for (T item : list)

    pass 1 of 10
    61int count = 0;62for (T item5 : list[5, 10, 3, 10, 7]) {63    if (item.equals(target)) {
    All 10 passes — pass 1 is the card above
    passitem
    15
    210
    33
    410
    57
    65
    710
    83
    910
    107
  29. count ← 1

    pass 1 of 4
    62for (T item : list) {63    if (item.equals(target10)) {64        count→ 1++;65    }
    All 4 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    30 1
    41 2
  30. return count;

    66    }67    return count2;68}
  31. System.out.println(" Count 10s: " + Counter.countMatching(nums, 10));

    82List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));
    output  Count 10s: 2
  32. count ← 0

    pass 2 of 2
    59class Counter {60    public static <T> int countMatching(List<T> list[5, 10, 3, 10, 7], T target10) {61        int count→ 0 = 0;62        for (T item : list) {
  33. return count;

    66    }67    return count2;68}
  34. System.out.println(" Count 10s: " + Counter.countMatching(nums, 10));

    82List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));
    output  Count 10s: 2
  35. count ← 0

    pass 1 of 2
    70public static <T extends Comparable<T>> int countGreater(71        List<T> list[5, 10, 3, 10, 7], T threshold5) {72    int count→ 0 = 0;73    for (T item : list) {
  36. for (T item : list)

    pass 1 of 10
    72int count = 0;73for (T item5 : list[5, 10, 3, 10, 7]) {74    if (item.compareTo(threshold) > 0) {
    All 10 passes — pass 1 is the card above
    passitem
    15
    210
    33
    410
    57
    65
    710
    83
    910
    107
  37. count ← 1

    pass 1 of 6
    73for (T item : list) {74    if (item.compareTo(threshold5) > 0) {75        count→ 1++;76    }
    All 6 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    32 3
    40 1
    51 2
    62 3
  38. return count;

    77    }78    return count3;79}
  39. System.out.println(" Count > 5: " + Counter.countGreater(nums, 5));

    83System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));
    output  Count > 5: 3
  40. count ← 0

    pass 2 of 2
    70public static <T extends Comparable<T>> int countGreater(71        List<T> list[5, 10, 3, 10, 7], T threshold5) {72    int count→ 0 = 0;73    for (T item : list) {
  41. return count;

    77    }78    return count3;79}
  42. System.out.println(" Count > 5: " + Counter.countGreater(nums, 5));

    83System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));8586System.out.println("\nCopy method:");
    output  Count > 5: 3
    
    Copy method:
    
    Copy method:
  43. public static <T extends Comparable<T>> void copyGreater( …

    94public static <T extends Comparable<T>> void copyGreater(95        List<T> source[1, 5, 3, 8, 2, 9], List<T> dest[], T threshold4) {96    dest.clear();97    for (T item : source) {
  44. for (T item : source)

    pass 1 of 6
    96dest.clear();97for (T item1 : source[1, 5, 3, 8, 2, 9]) {98    if (item.compareTo(threshold) > 0) {
    All 6 passes — pass 1 is the card above
    passitem
    11
    25
    33
    48
    52
    69
  45. if (item.compareTo(threshold) > 0)

    pass 1 of 3
    97for (T item : source) {98    if (item.compareTo(threshold4) > 0) {99        dest.add(item5);100    }
    All 3 passes — pass 1 is the card above
    passitem
    15
    28
    39
  46. System.out.println(" Copied > " + threshold + ": " + dst);

    109Copier.copyGreater(src, dst, threshold);110System.out.println("  Copied > " + threshold4 + ": " + dst[5, 8, 9]);111112System.out.println("\nMin/Max finder:");
    output  Copied > 4: [5, 8, 9]
      Copied > 4: [5, 8, 9]
    
    Min/Max finder:
    
    Min/Max finder:
  47. public static <T extends Comparable<T>> T min(T a, T b)

    114class MinMax {115    public static <T extends Comparable<T>> T min(T a5, T b10) {116        return a.compareTo(b10) < 0 ? a5 : b;117    }
  48. System.out.println(" max(5, 10): " + MinMax.max(5, 10));

    131System.out.println("  min(5, 10): " + MinMax.min(5, 10));132System.out.println("  max(5, 10): " + MinMax.max(5, 10));133System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));
  49. public static <T extends Comparable<T>> T max(T a, T b)

    119public static <T extends Comparable<T>> T max(T a5, T b10) {120    return a.compareTo(b10) > 0 ? a5 : b;121}
  50. System.out.println(" max(5, 10): " + MinMax.max(5, 10));

    131System.out.println("  min(5, 10): " + MinMax.min(5, 10));132System.out.println("  max(5, 10): " + MinMax.max(5, 10));133System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));
    output  max(5, 10): 10
  51. public static <T extends Comparable<T>> T clamp( T…

    pass 1 of 2
    123public static <T extends Comparable<T>> T clamp(124        T value15, T min0, T max10) {125    if (value.compareTo(min) < 0) return min;
  52. if (value.compareTo(max) > 0)

    125if (value.compareTo(min) < 0) return min;126if (value.compareTo(max10) > 0) return max;127return value;
  53. System.out.println(" clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));

    132    System.out.println("  max(5, 10): " + MinMax.max(5, 10));133    System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134    System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));135}
    output  clamp(15, 0, 10): 10
  54. public static <T extends Comparable<T>> T clamp( T…

    pass 2 of 2
    123public static <T extends Comparable<T>> T clamp(124        T value-5, T min0, T max10) {125    if (value.compareTo(min) < 0) return min;
  55. if (value.compareTo(min) < 0)

    124    T value, T min, T max) {125if (value.compareTo(min0) < 0) return min;126if (value.compareTo(max) > 0) return max;
  56. System.out.println(" clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));

    133    System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134    System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));135}
    output  clamp(-5, 0, 10): 0
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Bounded methods:\n");
    outputBounded methods:
    Bounded methods:
  2. max ← 5

    pass 1 of 2
    3public class BoundedMethods {4    public static <T extends Comparable<T>> T findMax(List<T> list[5, 2, 9, 1, 7]) {5        if (list.isEmpty()) {6            return null;7        }8        9        T max→ 5 = list.get(0);10        for (T item : list) {
  3. for (T item : list)

    pass 1 of 8
    9T max = list.get(0);10for (T item5 : list[5, 2, 9, 1, 7]) {11    if (item.compareTo(max) > 0) {
    All 8 passes — pass 1 is the card above
    passitemlistmax
    15[5, 2, 9, 1, 7]
    22[5, 2, 9, 1, 7]
    39[5, 2, 9, 1, 7]5 9
    41[5, 2, 9, 1, 7]
    57[5, 2, 9, 1, 7]
    6apple[apple, zebra, banana]
    7zebra[apple, zebra, banana]apple zebra
    8banana[apple, zebra, banana]
  4. max ← 9

    pass 1 of 2
    10for (T item : list) {11    if (item.compareTo(max5) > 0) {12        max→ 9 = item9;13    }
  5. return max;

    14    }15    return max9;16}
  6. System.out.println(" Max number: " + maxNum);

    22Integer maxNum = findMax(numbers);23System.out.println("  Max number: " + maxNum9);
    output  Max number: 9
      Max number: 9
  7. max ← apple

    pass 2 of 2
    3public class BoundedMethods {4    public static <T extends Comparable<T>> T findMax(List<T> list[apple, zebra, banana]) {5        if (list.isEmpty()) {6            return null;7        }8        9        T max→ apple = list.get(0);10        for (T item : list) {
  8. max ← zebra

    pass 2 of 2
    10for (T item : list) {11    if (item.compareTo(maxapple) > 0) {12        max→ zebra = itemzebra;13    }
  9. return max;

    14    }15    return maxzebra;16}
  10. System.out.println(" Max word: " + maxWord);

    26String maxWord = findMax(words);27System.out.println("  Max word: " + maxWordzebra);2829// Method can declare its own type parameters with bounds30// <T extends Type> before return type31// Bound applies only to that method32// Enables calling bounded type's methods3334System.out.println("\nNumeric operations:");3536class MathUtils {37    public static <T extends Number> double sum(List<T> numbers) {38        double total = 0;39        for (T num : numbers) {40            total += num.doubleValue();41        }42        return total;43    }44    45    public static <T extends Number> double average(List<T> numbers) {46        return sum(numbers) / numbers.size();47    }48}4950List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList));
    output  Max word: zebra
      Max word: zebra
    
    Numeric operations:
    
    Numeric operations:
  11. total ← 0.0

    pass 1 of 6
    36class MathUtils {37    public static <T extends Number> double sum(List<T> numbers[10, 20, 30]) {38        double total→ 0.0 = 0;39        for (T num : numbers) {
    All 6 passes — pass 1 is the card above
    passnumberstotal
    1[10, 20, 30]0.0
    2[10, 20, 30]0.0
    3[10, 20, 30]0.0
    4[10, 20, 30]0.0
    5[1.5, 2.5, 3.5]0.0
    6[1.5, 2.5, 3.5]0.0
  12. total ← 10.0

    pass 1 of 18
    38double total = 0;39for (T num10 : numbers[10, 20, 30]) {40    total→ 10.0 += num.doubleValue();41}
    18 passes — pass 1 is the card above
    passnumnumberstotal
    110[10, 20, 30]0.0 10.0
    220[10, 20, 30]10.0 30.0
    330[10, 20, 30]30.0 60.0
    410[10, 20, 30]0.0 10.0
    520[10, 20, 30]10.0 30.0
    630[10, 20, 30]30.0 60.0
    710[10, 20, 30]0.0 10.0
    820[10, 20, 30]10.0 30.0
    930[10, 20, 30]30.0 60.0
    ⋯ 7 more passes ⋯
    172.5[1.5, 2.5, 3.5]1.5 4.0
    183.5[1.5, 2.5, 3.5]4.0 7.5
  13. return total;

    41    }42    return total60.0;43}
  14. System.out.println(" Sum: " + MathUtils.sum(intList));

    50List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList));
    output  Sum: 60.0
  15. return total;

    41    }42    return total60.0;43}
  16. System.out.println(" Sum: " + MathUtils.sum(intList));

    50List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));
    output  Sum: 60.0
  17. public static <T extends Number> double average(List<T> numbers)

    pass 1 of 2
    45public static <T extends Number> double average(List<T> numbers[10, 20, 30]) {46    return sum(numbers[10, 20, 30]) / numbers.size();47}
  18. return total;

    41    }42    return total60.0;43}
  19. System.out.println(" Average: " + MathUtils.average(intList));

    51System.out.println("  Sum: " + MathUtils.sum(intList));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));
    output  Average: 20.0
  20. public static <T extends Number> double average(List<T> numbers)

    pass 2 of 2
    45public static <T extends Number> double average(List<T> numbers[10, 20, 30]) {46    return sum(numbers[10, 20, 30]) / numbers.size();47}
  21. return total;

    41    }42    return total60.0;43}
  22. System.out.println(" Average: " + MathUtils.average(intList));

    51System.out.println("  Sum: " + MathUtils.sum(intList));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));5354List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));
    output  Average: 20.0
  23. return total;

    41    }42    return total7.5;43}
  24. System.out.println(" Sum: " + MathUtils.sum(doubleList));

    54List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));
    output  Sum: 7.5
  25. return total;

    41    }42    return total7.5;43}
  26. System.out.println(" Sum: " + MathUtils.sum(doubleList));

    54List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));5657System.out.println("\nCount matching:");5859class Counter {60    public static <T> int countMatching(List<T> list, T target) {61        int count = 0;62        for (T item : list) {63            if (item.equals(target)) {64                count++;65            }66        }67        return count;68    }69    70    public static <T extends Comparable<T>> int countGreater(71            List<T> list, T threshold) {72        int count = 0;73        for (T item : list) {74            if (item.compareTo(threshold) > 0) {75                count++;76            }77        }78        return count;79    }80}8182List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));
    output  Sum: 7.5
    
    Count matching:
    
    Count matching:
  27. count ← 0

    pass 1 of 2
    59class Counter {60    public static <T> int countMatching(List<T> list[5, 10, 3, 10, 7], T target10) {61        int count→ 0 = 0;62        for (T item : list) {
  28. for (T item : list)

    pass 1 of 10
    61int count = 0;62for (T item5 : list[5, 10, 3, 10, 7]) {63    if (item.equals(target)) {
    All 10 passes — pass 1 is the card above
    passitem
    15
    210
    33
    410
    57
    65
    710
    83
    910
    107
  29. count ← 1

    pass 1 of 4
    62for (T item : list) {63    if (item.equals(target10)) {64        count→ 1++;65    }
    All 4 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    30 1
    41 2
  30. return count;

    66    }67    return count2;68}
  31. System.out.println(" Count 10s: " + Counter.countMatching(nums, 10));

    82List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));
    output  Count 10s: 2
  32. count ← 0

    pass 2 of 2
    59class Counter {60    public static <T> int countMatching(List<T> list[5, 10, 3, 10, 7], T target10) {61        int count→ 0 = 0;62        for (T item : list) {
  33. return count;

    66    }67    return count2;68}
  34. System.out.println(" Count 10s: " + Counter.countMatching(nums, 10));

    82List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));
    output  Count 10s: 2
  35. count ← 0

    pass 1 of 2
    70public static <T extends Comparable<T>> int countGreater(71        List<T> list[5, 10, 3, 10, 7], T threshold5) {72    int count→ 0 = 0;73    for (T item : list) {
  36. for (T item : list)

    pass 1 of 10
    72int count = 0;73for (T item5 : list[5, 10, 3, 10, 7]) {74    if (item.compareTo(threshold) > 0) {
    All 10 passes — pass 1 is the card above
    passitem
    15
    210
    33
    410
    57
    65
    710
    83
    910
    107
  37. count ← 1

    pass 1 of 6
    73for (T item : list) {74    if (item.compareTo(threshold5) > 0) {75        count→ 1++;76    }
    All 6 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    32 3
    40 1
    51 2
    62 3
  38. return count;

    77    }78    return count3;79}
  39. System.out.println(" Count > 5: " + Counter.countGreater(nums, 5));

    83System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));
    output  Count > 5: 3
  40. count ← 0

    pass 2 of 2
    70public static <T extends Comparable<T>> int countGreater(71        List<T> list[5, 10, 3, 10, 7], T threshold5) {72    int count→ 0 = 0;73    for (T item : list) {
  41. return count;

    77    }78    return count3;79}
  42. System.out.println(" Count > 5: " + Counter.countGreater(nums, 5));

    83System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));8586System.out.println("\nCopy method:");
    output  Count > 5: 3
    
    Copy method:
    
    Copy method:
  43. public static <T extends Comparable<T>> void copyGreater( …

    94public static <T extends Comparable<T>> void copyGreater(95        List<T> source[1, 5, 3, 8, 2, 9], List<T> dest[], T threshold6) {96    dest.clear();97    for (T item : source) {
  44. for (T item : source)

    pass 1 of 6
    96dest.clear();97for (T item1 : source[1, 5, 3, 8, 2, 9]) {98    if (item.compareTo(threshold) > 0) {
    All 6 passes — pass 1 is the card above
    passitemthreshold
    11
    25
    33
    486
    52
    696
  45. if (item.compareTo(threshold) > 0)

    pass 1 of 2
    97for (T item : source) {98    if (item.compareTo(threshold6) > 0) {99        dest.add(item8);100    }
  46. if (item.compareTo(threshold) > 0)

    pass 2 of 2
    97for (T item : source) {98    if (item.compareTo(threshold6) > 0) {99        dest.add(item9);100    }
  47. System.out.println(" Copied > " + threshold + ": " + dst);

    109Copier.copyGreater(src, dst, threshold);110System.out.println("  Copied > " + threshold6 + ": " + dst[8, 9]);111112System.out.println("\nMin/Max finder:");
    output  Copied > 6: [8, 9]
      Copied > 6: [8, 9]
    
    Min/Max finder:
    
    Min/Max finder:
  48. public static <T extends Comparable<T>> T min(T a, T b)

    114class MinMax {115    public static <T extends Comparable<T>> T min(T a5, T b10) {116        return a.compareTo(b10) < 0 ? a5 : b;117    }
  49. System.out.println(" max(5, 10): " + MinMax.max(5, 10));

    131System.out.println("  min(5, 10): " + MinMax.min(5, 10));132System.out.println("  max(5, 10): " + MinMax.max(5, 10));133System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));
  50. public static <T extends Comparable<T>> T max(T a, T b)

    119public static <T extends Comparable<T>> T max(T a5, T b10) {120    return a.compareTo(b10) > 0 ? a5 : b;121}
  51. System.out.println(" max(5, 10): " + MinMax.max(5, 10));

    131System.out.println("  min(5, 10): " + MinMax.min(5, 10));132System.out.println("  max(5, 10): " + MinMax.max(5, 10));133System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));
    output  max(5, 10): 10
  52. public static <T extends Comparable<T>> T clamp( T…

    pass 1 of 2
    123public static <T extends Comparable<T>> T clamp(124        T value15, T min0, T max10) {125    if (value.compareTo(min) < 0) return min;
  53. if (value.compareTo(max) > 0)

    125if (value.compareTo(min) < 0) return min;126if (value.compareTo(max10) > 0) return max;127return value;
  54. System.out.println(" clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));

    132    System.out.println("  max(5, 10): " + MinMax.max(5, 10));133    System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134    System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));135}
    output  clamp(15, 0, 10): 10
  55. public static <T extends Comparable<T>> T clamp( T…

    pass 2 of 2
    123public static <T extends Comparable<T>> T clamp(124        T value-5, T min0, T max10) {125    if (value.compareTo(min) < 0) return min;
  56. if (value.compareTo(min) < 0)

    124    T value, T min, T max) {125if (value.compareTo(min0) < 0) return min;126if (value.compareTo(max) > 0) return max;
  57. System.out.println(" clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));

    133    System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134    System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));135}
    output  clamp(-5, 0, 10): 0
  1. public static void main(String[] args)

    18public static void main(String[] args) {19    System.out.println("Bounded methods:\n");
    outputBounded methods:
    Bounded methods:
  2. max ← 5

    pass 1 of 2
    3public class BoundedMethods {4    public static <T extends Comparable<T>> T findMax(List<T> list[5, 2, 9, 1, 7]) {5        if (list.isEmpty()) {6            return null;7        }8        9        T max→ 5 = list.get(0);10        for (T item : list) {
  3. for (T item : list)

    pass 1 of 8
    9T max = list.get(0);10for (T item5 : list[5, 2, 9, 1, 7]) {11    if (item.compareTo(max) > 0) {
    All 8 passes — pass 1 is the card above
    passitemlistmax
    15[5, 2, 9, 1, 7]
    22[5, 2, 9, 1, 7]
    39[5, 2, 9, 1, 7]5 9
    41[5, 2, 9, 1, 7]
    57[5, 2, 9, 1, 7]
    6apple[apple, zebra, banana]
    7zebra[apple, zebra, banana]apple zebra
    8banana[apple, zebra, banana]
  4. max ← 9

    pass 1 of 2
    10for (T item : list) {11    if (item.compareTo(max5) > 0) {12        max→ 9 = item9;13    }
  5. return max;

    14    }15    return max9;16}
  6. System.out.println(" Max number: " + maxNum);

    22Integer maxNum = findMax(numbers);23System.out.println("  Max number: " + maxNum9);
    output  Max number: 9
      Max number: 9
  7. max ← apple

    pass 2 of 2
    3public class BoundedMethods {4    public static <T extends Comparable<T>> T findMax(List<T> list[apple, zebra, banana]) {5        if (list.isEmpty()) {6            return null;7        }8        9        T max→ apple = list.get(0);10        for (T item : list) {
  8. max ← zebra

    pass 2 of 2
    10for (T item : list) {11    if (item.compareTo(maxapple) > 0) {12        max→ zebra = itemzebra;13    }
  9. return max;

    14    }15    return maxzebra;16}
  10. System.out.println(" Max word: " + maxWord);

    26String maxWord = findMax(words);27System.out.println("  Max word: " + maxWordzebra);2829// Method can declare its own type parameters with bounds30// <T extends Type> before return type31// Bound applies only to that method32// Enables calling bounded type's methods3334System.out.println("\nNumeric operations:");3536class MathUtils {37    public static <T extends Number> double sum(List<T> numbers) {38        double total = 0;39        for (T num : numbers) {40            total += num.doubleValue();41        }42        return total;43    }44    45    public static <T extends Number> double average(List<T> numbers) {46        return sum(numbers) / numbers.size();47    }48}4950List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList));
    output  Max word: zebra
      Max word: zebra
    
    Numeric operations:
    
    Numeric operations:
  11. total ← 0.0

    pass 1 of 6
    36class MathUtils {37    public static <T extends Number> double sum(List<T> numbers[10, 20, 30]) {38        double total→ 0.0 = 0;39        for (T num : numbers) {
    All 6 passes — pass 1 is the card above
    passnumberstotal
    1[10, 20, 30]0.0
    2[10, 20, 30]0.0
    3[10, 20, 30]0.0
    4[10, 20, 30]0.0
    5[1.5, 2.5, 3.5]0.0
    6[1.5, 2.5, 3.5]0.0
  12. total ← 10.0

    pass 1 of 18
    38double total = 0;39for (T num10 : numbers[10, 20, 30]) {40    total→ 10.0 += num.doubleValue();41}
    18 passes — pass 1 is the card above
    passnumnumberstotal
    110[10, 20, 30]0.0 10.0
    220[10, 20, 30]10.0 30.0
    330[10, 20, 30]30.0 60.0
    410[10, 20, 30]0.0 10.0
    520[10, 20, 30]10.0 30.0
    630[10, 20, 30]30.0 60.0
    710[10, 20, 30]0.0 10.0
    820[10, 20, 30]10.0 30.0
    930[10, 20, 30]30.0 60.0
    ⋯ 7 more passes ⋯
    172.5[1.5, 2.5, 3.5]1.5 4.0
    183.5[1.5, 2.5, 3.5]4.0 7.5
  13. return total;

    41    }42    return total60.0;43}
  14. System.out.println(" Sum: " + MathUtils.sum(intList));

    50List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList));
    output  Sum: 60.0
  15. return total;

    41    }42    return total60.0;43}
  16. System.out.println(" Sum: " + MathUtils.sum(intList));

    50List<Integer> intList = Arrays.asList(10, 20, 30);51System.out.println("  Sum: " + MathUtils.sum(intList[10, 20, 30]));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));
    output  Sum: 60.0
  17. public static <T extends Number> double average(List<T> numbers)

    pass 1 of 2
    45public static <T extends Number> double average(List<T> numbers[10, 20, 30]) {46    return sum(numbers[10, 20, 30]) / numbers.size();47}
  18. return total;

    41    }42    return total60.0;43}
  19. System.out.println(" Average: " + MathUtils.average(intList));

    51System.out.println("  Sum: " + MathUtils.sum(intList));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));
    output  Average: 20.0
  20. public static <T extends Number> double average(List<T> numbers)

    pass 2 of 2
    45public static <T extends Number> double average(List<T> numbers[10, 20, 30]) {46    return sum(numbers[10, 20, 30]) / numbers.size();47}
  21. return total;

    41    }42    return total60.0;43}
  22. System.out.println(" Average: " + MathUtils.average(intList));

    51System.out.println("  Sum: " + MathUtils.sum(intList));52System.out.println("  Average: " + MathUtils.average(intList[10, 20, 30]));5354List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));
    output  Average: 20.0
  23. return total;

    41    }42    return total7.5;43}
  24. System.out.println(" Sum: " + MathUtils.sum(doubleList));

    54List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));
    output  Sum: 7.5
  25. return total;

    41    }42    return total7.5;43}
  26. System.out.println(" Sum: " + MathUtils.sum(doubleList));

    54List<Double> doubleList = Arrays.asList(1.5, 2.5, 3.5);55System.out.println("  Sum: " + MathUtils.sum(doubleList[1.5, 2.5, 3.5]));5657System.out.println("\nCount matching:");5859class Counter {60    public static <T> int countMatching(List<T> list, T target) {61        int count = 0;62        for (T item : list) {63            if (item.equals(target)) {64                count++;65            }66        }67        return count;68    }69    70    public static <T extends Comparable<T>> int countGreater(71            List<T> list, T threshold) {72        int count = 0;73        for (T item : list) {74            if (item.compareTo(threshold) > 0) {75                count++;76            }77        }78        return count;79    }80}8182List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));
    output  Sum: 7.5
    
    Count matching:
    
    Count matching:
  27. count ← 0

    pass 1 of 2
    59class Counter {60    public static <T> int countMatching(List<T> list[5, 10, 3, 10, 7], T target10) {61        int count→ 0 = 0;62        for (T item : list) {
  28. for (T item : list)

    pass 1 of 10
    61int count = 0;62for (T item5 : list[5, 10, 3, 10, 7]) {63    if (item.equals(target)) {
    All 10 passes — pass 1 is the card above
    passitem
    15
    210
    33
    410
    57
    65
    710
    83
    910
    107
  29. count ← 1

    pass 1 of 4
    62for (T item : list) {63    if (item.equals(target10)) {64        count→ 1++;65    }
    All 4 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    30 1
    41 2
  30. return count;

    66    }67    return count2;68}
  31. System.out.println(" Count 10s: " + Counter.countMatching(nums, 10));

    82List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums, 5));
    output  Count 10s: 2
  32. count ← 0

    pass 2 of 2
    59class Counter {60    public static <T> int countMatching(List<T> list[5, 10, 3, 10, 7], T target10) {61        int count→ 0 = 0;62        for (T item : list) {
  33. return count;

    66    }67    return count2;68}
  34. System.out.println(" Count 10s: " + Counter.countMatching(nums, 10));

    82List<Integer> nums = Arrays.asList(5, 10, 3, 10, 7);83System.out.println("  Count 10s: " + Counter.countMatching(nums[5, 10, 3, 10, 7], 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));
    output  Count 10s: 2
  35. count ← 0

    pass 1 of 2
    70public static <T extends Comparable<T>> int countGreater(71        List<T> list[5, 10, 3, 10, 7], T threshold5) {72    int count→ 0 = 0;73    for (T item : list) {
  36. for (T item : list)

    pass 1 of 10
    72int count = 0;73for (T item5 : list[5, 10, 3, 10, 7]) {74    if (item.compareTo(threshold) > 0) {
    All 10 passes — pass 1 is the card above
    passitem
    15
    210
    33
    410
    57
    65
    710
    83
    910
    107
  37. count ← 1

    pass 1 of 6
    73for (T item : list) {74    if (item.compareTo(threshold5) > 0) {75        count→ 1++;76    }
    All 6 passes — pass 1 is the card above
    passcount
    10 1
    21 2
    32 3
    40 1
    51 2
    62 3
  38. return count;

    77    }78    return count3;79}
  39. System.out.println(" Count > 5: " + Counter.countGreater(nums, 5));

    83System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));
    output  Count > 5: 3
  40. count ← 0

    pass 2 of 2
    70public static <T extends Comparable<T>> int countGreater(71        List<T> list[5, 10, 3, 10, 7], T threshold5) {72    int count→ 0 = 0;73    for (T item : list) {
  41. return count;

    77    }78    return count3;79}
  42. System.out.println(" Count > 5: " + Counter.countGreater(nums, 5));

    83System.out.println("  Count 10s: " + Counter.countMatching(nums, 10));84System.out.println("  Count > 5: " + Counter.countGreater(nums[5, 10, 3, 10, 7], 5));8586System.out.println("\nCopy method:");
    output  Count > 5: 3
    
    Copy method:
    
    Copy method:
  43. public static <T extends Comparable<T>> void copyGreater( …

    94public static <T extends Comparable<T>> void copyGreater(95        List<T> source[1, 5, 3, 8, 2, 9], List<T> dest[], T threshold8) {96    dest.clear();97    for (T item : source) {
  44. for (T item : source)

    pass 1 of 6
    96dest.clear();97for (T item1 : source[1, 5, 3, 8, 2, 9]) {98    if (item.compareTo(threshold) > 0) {
    All 6 passes — pass 1 is the card above
    passitemthreshold
    11
    25
    33
    48
    52
    698
  45. if (item.compareTo(threshold) > 0)

    97for (T item : source) {98    if (item.compareTo(threshold8) > 0) {99        dest.add(item9);100    }
  46. System.out.println(" Copied > " + threshold + ": " + dst);

    109Copier.copyGreater(src, dst, threshold);110System.out.println("  Copied > " + threshold8 + ": " + dst[9]);111112System.out.println("\nMin/Max finder:");
    output  Copied > 8: [9]
      Copied > 8: [9]
    
    Min/Max finder:
    
    Min/Max finder:
  47. public static <T extends Comparable<T>> T min(T a, T b)

    114class MinMax {115    public static <T extends Comparable<T>> T min(T a5, T b10) {116        return a.compareTo(b10) < 0 ? a5 : b;117    }
  48. System.out.println(" max(5, 10): " + MinMax.max(5, 10));

    131System.out.println("  min(5, 10): " + MinMax.min(5, 10));132System.out.println("  max(5, 10): " + MinMax.max(5, 10));133System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));
  49. public static <T extends Comparable<T>> T max(T a, T b)

    119public static <T extends Comparable<T>> T max(T a5, T b10) {120    return a.compareTo(b10) > 0 ? a5 : b;121}
  50. System.out.println(" max(5, 10): " + MinMax.max(5, 10));

    131System.out.println("  min(5, 10): " + MinMax.min(5, 10));132System.out.println("  max(5, 10): " + MinMax.max(5, 10));133System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));
    output  max(5, 10): 10
  51. public static <T extends Comparable<T>> T clamp( T…

    pass 1 of 2
    123public static <T extends Comparable<T>> T clamp(124        T value15, T min0, T max10) {125    if (value.compareTo(min) < 0) return min;
  52. if (value.compareTo(max) > 0)

    125if (value.compareTo(min) < 0) return min;126if (value.compareTo(max10) > 0) return max;127return value;
  53. System.out.println(" clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));

    132    System.out.println("  max(5, 10): " + MinMax.max(5, 10));133    System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134    System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));135}
    output  clamp(15, 0, 10): 10
  54. public static <T extends Comparable<T>> T clamp( T…

    pass 2 of 2
    123public static <T extends Comparable<T>> T clamp(124        T value-5, T min0, T max10) {125    if (value.compareTo(min) < 0) return min;
  55. if (value.compareTo(min) < 0)

    124    T value, T min, T max) {125if (value.compareTo(min0) < 0) return min;126if (value.compareTo(max) > 0) return max;
  56. System.out.println(" clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));

    133    System.out.println("  clamp(15, 0, 10): " + MinMax.clamp(15, 0, 10));134    System.out.println("  clamp(-5, 0, 10): " + MinMax.clamp(-5, 0, 10));135}
    output  clamp(-5, 0, 10): 0

<T extends Comparable<T>> T max(T a, T b) - can compare a and b.

Recursive bounds

Type parameter references itself in bound.

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

public class RecursiveBounds {
    static class SortedList<T extends Comparable<T>> {
        private List<T> items = new ArrayList<>();

        public void add(T item) {
            items.add(item);
            Collections.sort(items);
            System.out.println("  Added and sorted: " + item);
        }

        public T getMin() {
            return items.isEmpty() ? null : items.get(0);
        }

        public T getMax() {
            return items.isEmpty() ? null : items.get(items.size() - 1);
        }

        public List<T> getAll() {
            return new ArrayList<>(items);
        }
    }

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

        SortedList<Integer> numbers = new SortedList<>();
        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);

        System.out.println("  Min: " + numbers.getMin());
        System.out.println("  Max: " + numbers.getMax());
        System.out.println("  All: " + numbers.getAll());

        // <T extends Comparable<T>> is a recursive bound
        // T must be comparable to itself
        // Common pattern for sortable types
        // Ensures type-safe comparison

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

        enum Priority implements Comparable<Priority> {
            LOW, MEDIUM, HIGH
        }

        SortedList<Priority> priorities = new SortedList<>();
        priorities.add(Priority.HIGH);
        priorities.add(Priority.LOW);
        priorities.add(Priority.MEDIUM);

        System.out.println("  Sorted: " + priorities.getAll());

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

        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 + ")";
            }
        }

        SortedList<Person> people = new SortedList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        System.out.println("  By age: " + people.getAll());

        System.out.println("\nMax finder:");

        class MaxFinder {
            public static <T extends Comparable<T>> T max(T a, T b, T c) {
                T temp = a.compareTo(b) > 0 ? a : b;
                return temp.compareTo(c) > 0 ? temp : c;
            }

            public static <T extends Comparable<T>> T maxOf(List<T> items) {
                if (items.isEmpty()) {
                    return null;
                }
                T max = items.get(0);
                for (T item : items) {
                    if (item.compareTo(max) > 0) {
                        max = item;
                    }
                }
                return max;
            }
        }

        Integer maxNum = MaxFinder.max(5, 10, 3);
        System.out.println("  Max(5, 10, 3): " + maxNum);

        String maxStr = MaxFinder.max("apple", "zebra", "banana");
        System.out.println("  Max strings: " + maxStr);

        List<Double> doubles = Arrays.asList(3.14, 2.71, 1.41, 1.73);
        Double maxDouble = MaxFinder.maxOf(doubles);
        System.out.println("  Max double: " + maxDouble);

        System.out.println("\nBST node:");

        class TreeNode<T extends Comparable<T>> {
            T value;
            TreeNode<T> left;
            TreeNode<T> right;

            TreeNode(T value) {
                this.value = value;
            }

            public void insert(T newValue) {
                if (newValue.compareTo(value) < 0) {
                    if (left == null) {
                        left = new TreeNode<>(newValue);
                        System.out.println("  Inserted left: " + newValue);
                    } else {
                        left.insert(newValue);
                    }
                } else {
                    if (right == null) {
                        right = new TreeNode<>(newValue);
                        System.out.println("  Inserted right: " + newValue);
                    } else {
                        right.insert(newValue);
                    }
                }
            }

            public boolean contains(T target) {
                if (value.equals(target)) {
                    return true;
                } else if (target.compareTo(value) < 0) {
                    return left != null && left.contains(target);
                } else {
                    return right != null && right.contains(target);
                }
            }
        }

        TreeNode<Integer> root = new TreeNode<>(50);
        root.insert(30);
        root.insert(70);
        root.insert(20);
        root.insert(40);

        int searchTarget = 40;
        System.out.println("  Contains " + searchTarget + ": " +
                         root.contains(searchTarget));
        System.out.println("  Contains 60: " + root.contains(60));
    }
}
import java.util.*;

public class RecursiveBounds {
    static class SortedList<T extends Comparable<T>> {
        private List<T> items = new ArrayList<>();

        public void add(T item) {
            items.add(item);
            Collections.sort(items);
            System.out.println("  Added and sorted: " + item);
        }

        public T getMin() {
            return items.isEmpty() ? null : items.get(0);
        }

        public T getMax() {
            return items.isEmpty() ? null : items.get(items.size() - 1);
        }

        public List<T> getAll() {
            return new ArrayList<>(items);
        }
    }

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

        SortedList<Integer> numbers = new SortedList<>();
        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);

        System.out.println("  Min: " + numbers.getMin());
        System.out.println("  Max: " + numbers.getMax());
        System.out.println("  All: " + numbers.getAll());

        // <T extends Comparable<T>> is a recursive bound
        // T must be comparable to itself
        // Common pattern for sortable types
        // Ensures type-safe comparison

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

        enum Priority implements Comparable<Priority> {
            LOW, MEDIUM, HIGH
        }

        SortedList<Priority> priorities = new SortedList<>();
        priorities.add(Priority.HIGH);
        priorities.add(Priority.LOW);
        priorities.add(Priority.MEDIUM);

        System.out.println("  Sorted: " + priorities.getAll());

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

        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 + ")";
            }
        }

        SortedList<Person> people = new SortedList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        System.out.println("  By age: " + people.getAll());

        System.out.println("\nMax finder:");

        class MaxFinder {
            public static <T extends Comparable<T>> T max(T a, T b, T c) {
                T temp = a.compareTo(b) > 0 ? a : b;
                return temp.compareTo(c) > 0 ? temp : c;
            }

            public static <T extends Comparable<T>> T maxOf(List<T> items) {
                if (items.isEmpty()) {
                    return null;
                }
                T max = items.get(0);
                for (T item : items) {
                    if (item.compareTo(max) > 0) {
                        max = item;
                    }
                }
                return max;
            }
        }

        Integer maxNum = MaxFinder.max(5, 10, 3);
        System.out.println("  Max(5, 10, 3): " + maxNum);

        String maxStr = MaxFinder.max("apple", "zebra", "banana");
        System.out.println("  Max strings: " + maxStr);

        List<Double> doubles = Arrays.asList(3.14, 2.71, 1.41, 1.73);
        Double maxDouble = MaxFinder.maxOf(doubles);
        System.out.println("  Max double: " + maxDouble);

        System.out.println("\nBST node:");

        class TreeNode<T extends Comparable<T>> {
            T value;
            TreeNode<T> left;
            TreeNode<T> right;

            TreeNode(T value) {
                this.value = value;
            }

            public void insert(T newValue) {
                if (newValue.compareTo(value) < 0) {
                    if (left == null) {
                        left = new TreeNode<>(newValue);
                        System.out.println("  Inserted left: " + newValue);
                    } else {
                        left.insert(newValue);
                    }
                } else {
                    if (right == null) {
                        right = new TreeNode<>(newValue);
                        System.out.println("  Inserted right: " + newValue);
                    } else {
                        right.insert(newValue);
                    }
                }
            }

            public boolean contains(T target) {
                if (value.equals(target)) {
                    return true;
                } else if (target.compareTo(value) < 0) {
                    return left != null && left.contains(target);
                } else {
                    return right != null && right.contains(target);
                }
            }
        }

        TreeNode<Integer> root = new TreeNode<>(50);
        root.insert(30);
        root.insert(70);
        root.insert(20);
        root.insert(40);

        int searchTarget = 20;
        System.out.println("  Contains " + searchTarget + ": " +
                         root.contains(searchTarget));
        System.out.println("  Contains 60: " + root.contains(60));
    }
}
import java.util.*;

public class RecursiveBounds {
    static class SortedList<T extends Comparable<T>> {
        private List<T> items = new ArrayList<>();

        public void add(T item) {
            items.add(item);
            Collections.sort(items);
            System.out.println("  Added and sorted: " + item);
        }

        public T getMin() {
            return items.isEmpty() ? null : items.get(0);
        }

        public T getMax() {
            return items.isEmpty() ? null : items.get(items.size() - 1);
        }

        public List<T> getAll() {
            return new ArrayList<>(items);
        }
    }

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

        SortedList<Integer> numbers = new SortedList<>();
        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);

        System.out.println("  Min: " + numbers.getMin());
        System.out.println("  Max: " + numbers.getMax());
        System.out.println("  All: " + numbers.getAll());

        // <T extends Comparable<T>> is a recursive bound
        // T must be comparable to itself
        // Common pattern for sortable types
        // Ensures type-safe comparison

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

        enum Priority implements Comparable<Priority> {
            LOW, MEDIUM, HIGH
        }

        SortedList<Priority> priorities = new SortedList<>();
        priorities.add(Priority.HIGH);
        priorities.add(Priority.LOW);
        priorities.add(Priority.MEDIUM);

        System.out.println("  Sorted: " + priorities.getAll());

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

        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 + ")";
            }
        }

        SortedList<Person> people = new SortedList<>();
        people.add(new Person("Alice", 30));
        people.add(new Person("Bob", 25));
        people.add(new Person("Charlie", 35));

        System.out.println("  By age: " + people.getAll());

        System.out.println("\nMax finder:");

        class MaxFinder {
            public static <T extends Comparable<T>> T max(T a, T b, T c) {
                T temp = a.compareTo(b) > 0 ? a : b;
                return temp.compareTo(c) > 0 ? temp : c;
            }

            public static <T extends Comparable<T>> T maxOf(List<T> items) {
                if (items.isEmpty()) {
                    return null;
                }
                T max = items.get(0);
                for (T item : items) {
                    if (item.compareTo(max) > 0) {
                        max = item;
                    }
                }
                return max;
            }
        }

        Integer maxNum = MaxFinder.max(5, 10, 3);
        System.out.println("  Max(5, 10, 3): " + maxNum);

        String maxStr = MaxFinder.max("apple", "zebra", "banana");
        System.out.println("  Max strings: " + maxStr);

        List<Double> doubles = Arrays.asList(3.14, 2.71, 1.41, 1.73);
        Double maxDouble = MaxFinder.maxOf(doubles);
        System.out.println("  Max double: " + maxDouble);

        System.out.println("\nBST node:");

        class TreeNode<T extends Comparable<T>> {
            T value;
            TreeNode<T> left;
            TreeNode<T> right;

            TreeNode(T value) {
                this.value = value;
            }

            public void insert(T newValue) {
                if (newValue.compareTo(value) < 0) {
                    if (left == null) {
                        left = new TreeNode<>(newValue);
                        System.out.println("  Inserted left: " + newValue);
                    } else {
                        left.insert(newValue);
                    }
                } else {
                    if (right == null) {
                        right = new TreeNode<>(newValue);
                        System.out.println("  Inserted right: " + newValue);
                    } else {
                        right.insert(newValue);
                    }
                }
            }

            public boolean contains(T target) {
                if (value.equals(target)) {
                    return true;
                } else if (target.compareTo(value) < 0) {
                    return left != null && left.contains(target);
                } else {
                    return right != null && right.contains(target);
                }
            }
        }

        TreeNode<Integer> root = new TreeNode<>(50);
        root.insert(30);
        root.insert(70);
        root.insert(20);
        root.insert(40);

        int searchTarget = 60;
        System.out.println("  Contains " + searchTarget + ": " +
                         root.contains(searchTarget));
        System.out.println("  Contains 60: " + root.contains(60));
    }
}
  1. public static void main(String[] args)

    26public static void main(String[] args) {27    System.out.println("Recursive type bounds:\n");
    outputRecursive type bounds:
    Recursive type bounds:
  2. public void add(T item)

    pass 1 of 10
    7public void add(T item5) {8    items.add(item5);9    Collections.sort(items[5]);10    System.out.println("  Added and sorted: " + item5);11}
    output  Added and sorted: 5
    All 10 passes — pass 1 is the card above
    passitemitems
    15[5]
    22[5, 2] [2, 5]
    38[2, 5, 8]
    41[2, 5, 8, 1] [1, 2, 5, 8]
    5HIGH[HIGH]
    6LOW[HIGH, LOW] [LOW, HIGH]
    7MEDIUM[LOW, HIGH, MEDIUM] [LOW, MEDIUM, HIGH]
    8Alice(30)[Alice(30)]
    9Bob(25)[Alice(30), Bob(25)]
    10Charlie(35)[Bob(25), Alice(30), Charlie(35)]
  3. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());
  4. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());
    output  Min: 1
  5. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Min: 1
  6. System.out.println(" Max: " + numbers.getMax());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Max: 8
  7. System.out.println(" Max: " + numbers.getMax());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Max: 8
  8. System.out.println(" All: " + numbers.getAll());

    36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  All: [1, 2, 5, 8]
  9. System.out.println(" All: " + numbers.getAll());

    36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());3839// <T extends Comparable<T>> is a recursive bound40// T must be comparable to itself41// Common pattern for sortable types42// Ensures type-safe comparison4344System.out.println("\nWith enums:");
    output  All: [1, 2, 5, 8]
    
    With enums:
    
    With enums:
  10. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());
  11. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());
    output  Sorted: [LOW, MEDIUM, HIGH]
  12. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());5657System.out.println("\nCustom comparable:");
    output  Sorted: [LOW, MEDIUM, HIGH]
    
    Custom comparable:
    
    Custom comparable:
  13. this.name ← Alice, this.age ← 30

    pass 1 of 3
    63Person(String nameAlice, int age30) {64    this.name→ Alice = nameAlice;65    this.age→ 30 = age30;66}
    All 3 passes — pass 1 is the card above
    passnameagethis.namethis.age
    1Alice30Alice30
    2Bob25Bob25
    3Charlie35Charlie35
  14. @Override public int compareTo(Person other)

    pass 1 of 3
    68@Override69public int compareTo(Person otherAlice(30)) {70    return Integer.compare(this.age25, other.age30);71}
    All 3 passes — pass 1 is the card above
    passotherthis.ageother.age
    1Alice(30)2530
    2Bob(25)3025
    3Alice(30)3530
  15. items ← [Bob(25), Alice(30)]

    8    items.add(item);9    Collections.sort(items→ [Bob(25), Alice(30)]);10    System.out.println("  Added and sorted: " + itemBob(25));11}
    output  Added and sorted: Bob(25)
  16. Collections.sort(items);

    8        items.add(item);9        Collections.sort(items[Bob(25), Alice(30), Charlie(35)]);10        System.out.println("  Added and sorted: " + itemCharlie(35));11    }12    13    public T getMin() {14        return items.isEmpty() ? null : items.get(0);15    }16    17    public T getMax() {18        return items.isEmpty() ? null : items.get(items.size() - 1);19    }20    21    public List<T> getAll() {22        return new ArrayList<>(items);23    }24}2526public static void main(String[] args) {27    System.out.println("Recursive type bounds:\n");28    29    SortedList<Integer> numbers = new SortedList<>();30    numbers.add(5);31    numbers.add(2);32    numbers.add(8);33    numbers.add(1);34    35    System.out.println("  Min: " + numbers.getMin());36    System.out.println("  Max: " + numbers.getMax());37    System.out.println("  All: " + numbers.getAll());38    39    // <T extends Comparable<T>> is a recursive bound40    // T must be comparable to itself41    // Common pattern for sortable types42    // Ensures type-safe comparison43    44    System.out.println("\nWith enums:");45    46    enum Priority implements Comparable<Priority> {47        LOW, MEDIUM, HIGH48    }49    50    SortedList<Priority> priorities = new SortedList<>();51    priorities.add(Priority.HIGH);52    priorities.add(Priority.LOW);53    priorities.add(Priority.MEDIUM);54    55    System.out.println("  Sorted: " + priorities.getAll());56    57    System.out.println("\nCustom comparable:");58    59    class Person implements Comparable<Person> {60        String name;61        int age;62        63        Person(String name, int age) {64            this.name = name;65            this.age = age;66        }67        68        @Override69        public int compareTo(Person other) {70            return Integer.compare(this.age, other.age);71        }72        73        @Override74        public String toString() {75            return name + "(" + age + ")";76        }77    }78    79    SortedList<Person> people = new SortedList<>();80    people.add(new Person("Alice", 30));81    people.add(new Person("Bob", 25));82    people.add(new Person("Charlie", 35));83    84    System.out.println("  By age: " + people.getAll());
    output  Added and sorted: Charlie(35)
  17. System.out.println(" By age: " + people.getAll());

    84System.out.println("  By age: " + people.getAll());
    output  By age: [Bob(25), Alice(30), Charlie(35)]
  18. System.out.println(" By age: " + people.getAll());

    84System.out.println("  By age: " + people.getAll());8586System.out.println("\nMax finder:");
    output  By age: [Bob(25), Alice(30), Charlie(35)]
    
    Max finder:
    
    Max finder:
  19. temp ← 10

    pass 1 of 2
    88class MaxFinder {89    public static <T extends Comparable<T>> T max(T a5, T b10, T c3) {90        T temp→ 10 = a.compareTo(b10) > 0 ? a5 : b;91        return temp.compareTo(c3) > 0 ? temp10 : c;92    }
  20. System.out.println(" Max(5, 10, 3): " + maxNum);

    108Integer maxNum = MaxFinder.max(5, 10, 3);109System.out.println("  Max(5, 10, 3): " + maxNum10);
    output  Max(5, 10, 3): 10
      Max(5, 10, 3): 10
  21. temp ← zebra

    pass 2 of 2
    88class MaxFinder {89    public static <T extends Comparable<T>> T max(T aapple, T bzebra, T cbanana) {90        T temp→ zebra = a.compareTo(bzebra) > 0 ? aapple : b;91        return temp.compareTo(cbanana) > 0 ? tempzebra : c;92    }
  22. System.out.println(" Max strings: " + maxStr);

    111String maxStr = MaxFinder.max("apple", "zebra", "banana");112System.out.println("  Max strings: " + maxStrzebra);
    output  Max strings: zebra
      Max strings: zebra
  23. max ← 3.14

    94public static <T extends Comparable<T>> T maxOf(List<T> items[3.14, 2.71, 1.41, 1.73]) {95    if (items.isEmpty()) {96        return null;97    }98    T max→ 3.14 = items.get(0);99    for (T item : items) {
  24. for (T item : items)

    pass 1 of 4
    98T max = items.get(0);99for (T item3.14 : items[3.14, 2.71, 1.41, 1.73]) {100    if (item.compareTo(max) > 0) {
    All 4 passes — pass 1 is the card above
    passitem
    13.14
    22.71
    31.41
    41.73
  25. return max;

    103    }104    return max3.14;105}
  26. System.out.println(" Max double: " + maxDouble);

    115Double maxDouble = MaxFinder.maxOf(doubles);116System.out.println("  Max double: " + maxDouble3.14);117118System.out.println("\nBST node:");
    output  Max double: 3.14
      Max double: 3.14
    
    BST node:
    
    BST node:
  27. this.value ← 50

    pass 1 of 5
    125TreeNode(T value50) {126    this.value→ 50 = value50;127}
    All 5 passes — pass 1 is the card above
    passvaluethis.value
    15050
    23030
    37070
    42020
    54040
  28. root.insert(30);

    158TreeNode<Integer> root = new TreeNode<>(50);159root.insert(30);160root.insert(70);
  29. public void insert(T newValue)

    pass 1 of 6
    129public void insert(T newValue30) {130    if (newValue.compareTo(value) < 0) {
    All 6 passes — pass 1 is the card above
    passnewValueleftright
    130null
    270null
    320
    420null
    540
    640null
  30. if (newValue.compareTo(value) < 0)

    pass 1 of 4
    129public void insert(T newValue) {130    if (newValue.compareTo(value50) < 0) {131        if (left == null) {
    All 4 passes — pass 1 is the card above
    passvalueleftnewValueright
    150null
    25020
    330null
    45040null
  31. if (left == null)

    pass 1 of 2
    130if (newValue.compareTo(value) < 0) {131    if (leftnull == null) {132        left = new TreeNode<>(newValue);133        System.out.println("  Inserted left: " + newValue);
  32. left ← ⟨RecursiveBounds$1TreeNode A⟩

    131if (left == null) {132    left→ ⟨RecursiveBounds$1TreeNode A⟩ = new TreeNode<>(newValue);133    System.out.println("  Inserted left: " + newValue30);134} else {
    output  Inserted left: 30
  33. root.insert(30);

    158TreeNode<Integer> root = new TreeNode<>(50);159root.insert(30);160root.insert(70);161root.insert(20);
  34. if (right == null)

    pass 1 of 2
    137} else {138    if (rightnull == null) {139        right = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue);
  35. right ← ⟨RecursiveBounds$1TreeNode B⟩

    138if (right == null) {139    right→ ⟨RecursiveBounds$1TreeNode B⟩ = new TreeNode<>(newValue);140    System.out.println("  Inserted right: " + newValue70);141} else {
    output  Inserted right: 70
  36. root.insert(70);

    159root.insert(30);160root.insert(70);161root.insert(20);162root.insert(40);
  37. else

    pass 1 of 2
    133    System.out.println("  Inserted left: " + newValue);134} else {135    left.insert(newValue20);136}
  38. if (left == null)

    pass 2 of 2
    130if (newValue.compareTo(value) < 0) {131    if (leftnull == null) {132        left = new TreeNode<>(newValue);133        System.out.println("  Inserted left: " + newValue);
  39. left ← ⟨RecursiveBounds$1TreeNode C⟩

    131if (left == null) {132    left→ ⟨RecursiveBounds$1TreeNode C⟩ = new TreeNode<>(newValue);133    System.out.println("  Inserted left: " + newValue20);134} else {
    output  Inserted left: 20
  40. left.insert(newValue);

    134} else {135    left.insert(newValue20);136}
  41. root.insert(20);

    160root.insert(70);161root.insert(20);162root.insert(40);
  42. else

    pass 2 of 2
    133    System.out.println("  Inserted left: " + newValue);134} else {135    left.insert(newValue40);136}
  43. if (right == null)

    pass 2 of 2
    137} else {138    if (rightnull == null) {139        right = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue);
  44. right ← ⟨RecursiveBounds$1TreeNode D⟩

    134    } else {135        left.insert(newValue40);136    }137} else {138    if (right == null) {139        right→ ⟨RecursiveBounds$1TreeNode D⟩ = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue40);141    } else {
    output  Inserted right: 40
  45. searchTarget ← 40

    161root.insert(20);162root.insert(40);163164int searchTarget→ 40 = 40; //@searchTarget=40, 20, 60165System.out.println("  Contains " + searchTarget40 + ": " +166                 root.contains(searchTarget40));167System.out.println("  Contains 60: " + root.contains(60));
  46. public boolean contains(T target)

    pass 1 of 5
    147public boolean contains(T target40) {148    if (value.equals(target)) {
    All 5 passes — pass 1 is the card above
    passtargetvalueleftright
    14050⟨RecursiveBounds$1TreeNode A⟩
    240⟨RecursiveBounds$1TreeNode D⟩
    340
    460⟨RecursiveBounds$1TreeNode B⟩
    56070null
  47. if (target.compareTo(value) < 0)

    pass 1 of 2
    149    return true;150} else if (target.compareTo(value50) < 0) {151    return left⟨RecursiveBounds$1TreeNode A⟩ != null && left.contains(target40);152} else {
  48. else

    pass 1 of 2
    151    return left != null && left.contains(target);152} else {153    return right⟨RecursiveBounds$1TreeNode D⟩ != null && right.contains(target40);154}
  49. if (value.equals(target))

    147public boolean contains(T target) {148    if (value.equals(target40)) {149        return true;150    } else if (target.compareTo(value) < 0) {
  50. System.out.println(" Contains " + searchTarget + ": " +

    164    int searchTarget = 40; //@searchTarget=40, 20, 60165    System.out.println("  Contains " + searchTarget40 + ": " +166                     root.contains(searchTarget40));167    System.out.println("  Contains 60: " + root.contains(60));168}
    output  Contains 40: true
  51. else

    pass 2 of 2
    151    return left != null && left.contains(target);152} else {153    return right⟨RecursiveBounds$1TreeNode B⟩ != null && right.contains(target60);154}
  52. if (target.compareTo(value) < 0)

    pass 2 of 2
    149    return true;150} else if (target.compareTo(value70) < 0) {151    return leftnull != null && left.contains(target60);152} else {
  53. System.out.println(" Contains 60: " + root.contains(60));

    166                     root.contains(searchTarget));167    System.out.println("  Contains 60: " + root.contains(60));168}
    output  Contains 60: false
  1. public static void main(String[] args)

    26public static void main(String[] args) {27    System.out.println("Recursive type bounds:\n");
    outputRecursive type bounds:
    Recursive type bounds:
  2. public void add(T item)

    pass 1 of 10
    7public void add(T item5) {8    items.add(item5);9    Collections.sort(items[5]);10    System.out.println("  Added and sorted: " + item5);11}
    output  Added and sorted: 5
    All 10 passes — pass 1 is the card above
    passitemitems
    15[5]
    22[5, 2] [2, 5]
    38[2, 5, 8]
    41[2, 5, 8, 1] [1, 2, 5, 8]
    5HIGH[HIGH]
    6LOW[HIGH, LOW] [LOW, HIGH]
    7MEDIUM[LOW, HIGH, MEDIUM] [LOW, MEDIUM, HIGH]
    8Alice(30)[Alice(30)]
    9Bob(25)[Alice(30), Bob(25)]
    10Charlie(35)[Bob(25), Alice(30), Charlie(35)]
  3. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());
  4. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());
    output  Min: 1
  5. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Min: 1
  6. System.out.println(" Max: " + numbers.getMax());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Max: 8
  7. System.out.println(" Max: " + numbers.getMax());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Max: 8
  8. System.out.println(" All: " + numbers.getAll());

    36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  All: [1, 2, 5, 8]
  9. System.out.println(" All: " + numbers.getAll());

    36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());3839// <T extends Comparable<T>> is a recursive bound40// T must be comparable to itself41// Common pattern for sortable types42// Ensures type-safe comparison4344System.out.println("\nWith enums:");
    output  All: [1, 2, 5, 8]
    
    With enums:
    
    With enums:
  10. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());
  11. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());
    output  Sorted: [LOW, MEDIUM, HIGH]
  12. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());5657System.out.println("\nCustom comparable:");
    output  Sorted: [LOW, MEDIUM, HIGH]
    
    Custom comparable:
    
    Custom comparable:
  13. this.name ← Alice, this.age ← 30

    pass 1 of 3
    63Person(String nameAlice, int age30) {64    this.name→ Alice = nameAlice;65    this.age→ 30 = age30;66}
    All 3 passes — pass 1 is the card above
    passnameagethis.namethis.age
    1Alice30Alice30
    2Bob25Bob25
    3Charlie35Charlie35
  14. @Override public int compareTo(Person other)

    pass 1 of 3
    68@Override69public int compareTo(Person otherAlice(30)) {70    return Integer.compare(this.age25, other.age30);71}
    All 3 passes — pass 1 is the card above
    passotherthis.ageother.age
    1Alice(30)2530
    2Bob(25)3025
    3Alice(30)3530
  15. items ← [Bob(25), Alice(30)]

    8    items.add(item);9    Collections.sort(items→ [Bob(25), Alice(30)]);10    System.out.println("  Added and sorted: " + itemBob(25));11}
    output  Added and sorted: Bob(25)
  16. Collections.sort(items);

    8        items.add(item);9        Collections.sort(items[Bob(25), Alice(30), Charlie(35)]);10        System.out.println("  Added and sorted: " + itemCharlie(35));11    }12    13    public T getMin() {14        return items.isEmpty() ? null : items.get(0);15    }16    17    public T getMax() {18        return items.isEmpty() ? null : items.get(items.size() - 1);19    }20    21    public List<T> getAll() {22        return new ArrayList<>(items);23    }24}2526public static void main(String[] args) {27    System.out.println("Recursive type bounds:\n");28    29    SortedList<Integer> numbers = new SortedList<>();30    numbers.add(5);31    numbers.add(2);32    numbers.add(8);33    numbers.add(1);34    35    System.out.println("  Min: " + numbers.getMin());36    System.out.println("  Max: " + numbers.getMax());37    System.out.println("  All: " + numbers.getAll());38    39    // <T extends Comparable<T>> is a recursive bound40    // T must be comparable to itself41    // Common pattern for sortable types42    // Ensures type-safe comparison43    44    System.out.println("\nWith enums:");45    46    enum Priority implements Comparable<Priority> {47        LOW, MEDIUM, HIGH48    }49    50    SortedList<Priority> priorities = new SortedList<>();51    priorities.add(Priority.HIGH);52    priorities.add(Priority.LOW);53    priorities.add(Priority.MEDIUM);54    55    System.out.println("  Sorted: " + priorities.getAll());56    57    System.out.println("\nCustom comparable:");58    59    class Person implements Comparable<Person> {60        String name;61        int age;62        63        Person(String name, int age) {64            this.name = name;65            this.age = age;66        }67        68        @Override69        public int compareTo(Person other) {70            return Integer.compare(this.age, other.age);71        }72        73        @Override74        public String toString() {75            return name + "(" + age + ")";76        }77    }78    79    SortedList<Person> people = new SortedList<>();80    people.add(new Person("Alice", 30));81    people.add(new Person("Bob", 25));82    people.add(new Person("Charlie", 35));83    84    System.out.println("  By age: " + people.getAll());
    output  Added and sorted: Charlie(35)
  17. System.out.println(" By age: " + people.getAll());

    84System.out.println("  By age: " + people.getAll());
    output  By age: [Bob(25), Alice(30), Charlie(35)]
  18. System.out.println(" By age: " + people.getAll());

    84System.out.println("  By age: " + people.getAll());8586System.out.println("\nMax finder:");
    output  By age: [Bob(25), Alice(30), Charlie(35)]
    
    Max finder:
    
    Max finder:
  19. temp ← 10

    pass 1 of 2
    88class MaxFinder {89    public static <T extends Comparable<T>> T max(T a5, T b10, T c3) {90        T temp→ 10 = a.compareTo(b10) > 0 ? a5 : b;91        return temp.compareTo(c3) > 0 ? temp10 : c;92    }
  20. System.out.println(" Max(5, 10, 3): " + maxNum);

    108Integer maxNum = MaxFinder.max(5, 10, 3);109System.out.println("  Max(5, 10, 3): " + maxNum10);
    output  Max(5, 10, 3): 10
      Max(5, 10, 3): 10
  21. temp ← zebra

    pass 2 of 2
    88class MaxFinder {89    public static <T extends Comparable<T>> T max(T aapple, T bzebra, T cbanana) {90        T temp→ zebra = a.compareTo(bzebra) > 0 ? aapple : b;91        return temp.compareTo(cbanana) > 0 ? tempzebra : c;92    }
  22. System.out.println(" Max strings: " + maxStr);

    111String maxStr = MaxFinder.max("apple", "zebra", "banana");112System.out.println("  Max strings: " + maxStrzebra);
    output  Max strings: zebra
      Max strings: zebra
  23. max ← 3.14

    94public static <T extends Comparable<T>> T maxOf(List<T> items[3.14, 2.71, 1.41, 1.73]) {95    if (items.isEmpty()) {96        return null;97    }98    T max→ 3.14 = items.get(0);99    for (T item : items) {
  24. for (T item : items)

    pass 1 of 4
    98T max = items.get(0);99for (T item3.14 : items[3.14, 2.71, 1.41, 1.73]) {100    if (item.compareTo(max) > 0) {
    All 4 passes — pass 1 is the card above
    passitem
    13.14
    22.71
    31.41
    41.73
  25. return max;

    103    }104    return max3.14;105}
  26. System.out.println(" Max double: " + maxDouble);

    115Double maxDouble = MaxFinder.maxOf(doubles);116System.out.println("  Max double: " + maxDouble3.14);117118System.out.println("\nBST node:");
    output  Max double: 3.14
      Max double: 3.14
    
    BST node:
    
    BST node:
  27. this.value ← 50

    pass 1 of 5
    125TreeNode(T value50) {126    this.value→ 50 = value50;127}
    All 5 passes — pass 1 is the card above
    passvaluethis.value
    15050
    23030
    37070
    42020
    54040
  28. root.insert(30);

    158TreeNode<Integer> root = new TreeNode<>(50);159root.insert(30);160root.insert(70);
  29. public void insert(T newValue)

    pass 1 of 6
    129public void insert(T newValue30) {130    if (newValue.compareTo(value) < 0) {
    All 6 passes — pass 1 is the card above
    passnewValueleftright
    130null
    270null
    320
    420null
    540
    640null
  30. if (newValue.compareTo(value) < 0)

    pass 1 of 4
    129public void insert(T newValue) {130    if (newValue.compareTo(value50) < 0) {131        if (left == null) {
    All 4 passes — pass 1 is the card above
    passvalueleftnewValueright
    150null
    25020
    330null
    45040null
  31. if (left == null)

    pass 1 of 2
    130if (newValue.compareTo(value) < 0) {131    if (leftnull == null) {132        left = new TreeNode<>(newValue);133        System.out.println("  Inserted left: " + newValue);
  32. left ← ⟨RecursiveBounds$1TreeNode A⟩

    131if (left == null) {132    left→ ⟨RecursiveBounds$1TreeNode A⟩ = new TreeNode<>(newValue);133    System.out.println("  Inserted left: " + newValue30);134} else {
    output  Inserted left: 30
  33. root.insert(30);

    158TreeNode<Integer> root = new TreeNode<>(50);159root.insert(30);160root.insert(70);161root.insert(20);
  34. if (right == null)

    pass 1 of 2
    137} else {138    if (rightnull == null) {139        right = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue);
  35. right ← ⟨RecursiveBounds$1TreeNode B⟩

    138if (right == null) {139    right→ ⟨RecursiveBounds$1TreeNode B⟩ = new TreeNode<>(newValue);140    System.out.println("  Inserted right: " + newValue70);141} else {
    output  Inserted right: 70
  36. root.insert(70);

    159root.insert(30);160root.insert(70);161root.insert(20);162root.insert(40);
  37. else

    pass 1 of 2
    133    System.out.println("  Inserted left: " + newValue);134} else {135    left.insert(newValue20);136}
  38. if (left == null)

    pass 2 of 2
    130if (newValue.compareTo(value) < 0) {131    if (leftnull == null) {132        left = new TreeNode<>(newValue);133        System.out.println("  Inserted left: " + newValue);
  39. left ← ⟨RecursiveBounds$1TreeNode C⟩

    131if (left == null) {132    left→ ⟨RecursiveBounds$1TreeNode C⟩ = new TreeNode<>(newValue);133    System.out.println("  Inserted left: " + newValue20);134} else {
    output  Inserted left: 20
  40. left.insert(newValue);

    134} else {135    left.insert(newValue20);136}
  41. root.insert(20);

    160root.insert(70);161root.insert(20);162root.insert(40);
  42. else

    pass 2 of 2
    133    System.out.println("  Inserted left: " + newValue);134} else {135    left.insert(newValue40);136}
  43. if (right == null)

    pass 2 of 2
    137} else {138    if (rightnull == null) {139        right = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue);
  44. right ← ⟨RecursiveBounds$1TreeNode D⟩

    134    } else {135        left.insert(newValue40);136    }137} else {138    if (right == null) {139        right→ ⟨RecursiveBounds$1TreeNode D⟩ = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue40);141    } else {
    output  Inserted right: 40
  45. searchTarget ← 20

    161root.insert(20);162root.insert(40);163164int searchTarget→ 20 = 20;165System.out.println("  Contains " + searchTarget20 + ": " +166                 root.contains(searchTarget20));167System.out.println("  Contains 60: " + root.contains(60));
  46. public boolean contains(T target)

    pass 1 of 5
    147public boolean contains(T target20) {148    if (value.equals(target)) {
    All 5 passes — pass 1 is the card above
    passtargetright
    120
    220
    320
    460⟨RecursiveBounds$1TreeNode B⟩
    560
  47. if (target.compareTo(value) < 0)

    pass 1 of 3
    149    return true;150} else if (target.compareTo(value50) < 0) {151    return left⟨RecursiveBounds$1TreeNode A⟩ != null && left.contains(target20);152} else {
    All 3 passes — pass 1 is the card above
    passvaluelefttarget
    150⟨RecursiveBounds$1TreeNode A⟩20
    230⟨RecursiveBounds$1TreeNode C⟩20
    370null60
  48. if (value.equals(target))

    147public boolean contains(T target) {148    if (value.equals(target20)) {149        return true;150    } else if (target.compareTo(value) < 0) {
  49. System.out.println(" Contains " + searchTarget + ": " +

    164    int searchTarget = 20;165    System.out.println("  Contains " + searchTarget20 + ": " +166                     root.contains(searchTarget20));167    System.out.println("  Contains 60: " + root.contains(60));168}
    output  Contains 20: true
  50. else

    151    return left != null && left.contains(target);152} else {153    return right⟨RecursiveBounds$1TreeNode B⟩ != null && right.contains(target60);154}
  51. System.out.println(" Contains 60: " + root.contains(60));

    166                     root.contains(searchTarget));167    System.out.println("  Contains 60: " + root.contains(60));168}
    output  Contains 60: false
  1. public static void main(String[] args)

    26public static void main(String[] args) {27    System.out.println("Recursive type bounds:\n");
    outputRecursive type bounds:
    Recursive type bounds:
  2. public void add(T item)

    pass 1 of 10
    7public void add(T item5) {8    items.add(item5);9    Collections.sort(items[5]);10    System.out.println("  Added and sorted: " + item5);11}
    output  Added and sorted: 5
    All 10 passes — pass 1 is the card above
    passitemitems
    15[5]
    22[5, 2] [2, 5]
    38[2, 5, 8]
    41[2, 5, 8, 1] [1, 2, 5, 8]
    5HIGH[HIGH]
    6LOW[HIGH, LOW] [LOW, HIGH]
    7MEDIUM[LOW, HIGH, MEDIUM] [LOW, MEDIUM, HIGH]
    8Alice(30)[Alice(30)]
    9Bob(25)[Alice(30), Bob(25)]
    10Charlie(35)[Bob(25), Alice(30), Charlie(35)]
  3. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());
  4. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());
    output  Min: 1
  5. System.out.println(" Min: " + numbers.getMin());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Min: 1
  6. System.out.println(" Max: " + numbers.getMax());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Max: 8
  7. System.out.println(" Max: " + numbers.getMax());

    35System.out.println("  Min: " + numbers.getMin());36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  Max: 8
  8. System.out.println(" All: " + numbers.getAll());

    36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());
    output  All: [1, 2, 5, 8]
  9. System.out.println(" All: " + numbers.getAll());

    36System.out.println("  Max: " + numbers.getMax());37System.out.println("  All: " + numbers.getAll());3839// <T extends Comparable<T>> is a recursive bound40// T must be comparable to itself41// Common pattern for sortable types42// Ensures type-safe comparison4344System.out.println("\nWith enums:");
    output  All: [1, 2, 5, 8]
    
    With enums:
    
    With enums:
  10. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());
  11. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());
    output  Sorted: [LOW, MEDIUM, HIGH]
  12. System.out.println(" Sorted: " + priorities.getAll());

    55System.out.println("  Sorted: " + priorities.getAll());5657System.out.println("\nCustom comparable:");
    output  Sorted: [LOW, MEDIUM, HIGH]
    
    Custom comparable:
    
    Custom comparable:
  13. this.name ← Alice, this.age ← 30

    pass 1 of 3
    63Person(String nameAlice, int age30) {64    this.name→ Alice = nameAlice;65    this.age→ 30 = age30;66}
    All 3 passes — pass 1 is the card above
    passnameagethis.namethis.age
    1Alice30Alice30
    2Bob25Bob25
    3Charlie35Charlie35
  14. @Override public int compareTo(Person other)

    pass 1 of 3
    68@Override69public int compareTo(Person otherAlice(30)) {70    return Integer.compare(this.age25, other.age30);71}
    All 3 passes — pass 1 is the card above
    passotherthis.ageother.age
    1Alice(30)2530
    2Bob(25)3025
    3Alice(30)3530
  15. items ← [Bob(25), Alice(30)]

    8    items.add(item);9    Collections.sort(items→ [Bob(25), Alice(30)]);10    System.out.println("  Added and sorted: " + itemBob(25));11}
    output  Added and sorted: Bob(25)
  16. Collections.sort(items);

    8        items.add(item);9        Collections.sort(items[Bob(25), Alice(30), Charlie(35)]);10        System.out.println("  Added and sorted: " + itemCharlie(35));11    }12    13    public T getMin() {14        return items.isEmpty() ? null : items.get(0);15    }16    17    public T getMax() {18        return items.isEmpty() ? null : items.get(items.size() - 1);19    }20    21    public List<T> getAll() {22        return new ArrayList<>(items);23    }24}2526public static void main(String[] args) {27    System.out.println("Recursive type bounds:\n");28    29    SortedList<Integer> numbers = new SortedList<>();30    numbers.add(5);31    numbers.add(2);32    numbers.add(8);33    numbers.add(1);34    35    System.out.println("  Min: " + numbers.getMin());36    System.out.println("  Max: " + numbers.getMax());37    System.out.println("  All: " + numbers.getAll());38    39    // <T extends Comparable<T>> is a recursive bound40    // T must be comparable to itself41    // Common pattern for sortable types42    // Ensures type-safe comparison43    44    System.out.println("\nWith enums:");45    46    enum Priority implements Comparable<Priority> {47        LOW, MEDIUM, HIGH48    }49    50    SortedList<Priority> priorities = new SortedList<>();51    priorities.add(Priority.HIGH);52    priorities.add(Priority.LOW);53    priorities.add(Priority.MEDIUM);54    55    System.out.println("  Sorted: " + priorities.getAll());56    57    System.out.println("\nCustom comparable:");58    59    class Person implements Comparable<Person> {60        String name;61        int age;62        63        Person(String name, int age) {64            this.name = name;65            this.age = age;66        }67        68        @Override69        public int compareTo(Person other) {70            return Integer.compare(this.age, other.age);71        }72        73        @Override74        public String toString() {75            return name + "(" + age + ")";76        }77    }78    79    SortedList<Person> people = new SortedList<>();80    people.add(new Person("Alice", 30));81    people.add(new Person("Bob", 25));82    people.add(new Person("Charlie", 35));83    84    System.out.println("  By age: " + people.getAll());
    output  Added and sorted: Charlie(35)
  17. System.out.println(" By age: " + people.getAll());

    84System.out.println("  By age: " + people.getAll());
    output  By age: [Bob(25), Alice(30), Charlie(35)]
  18. System.out.println(" By age: " + people.getAll());

    84System.out.println("  By age: " + people.getAll());8586System.out.println("\nMax finder:");
    output  By age: [Bob(25), Alice(30), Charlie(35)]
    
    Max finder:
    
    Max finder:
  19. temp ← 10

    pass 1 of 2
    88class MaxFinder {89    public static <T extends Comparable<T>> T max(T a5, T b10, T c3) {90        T temp→ 10 = a.compareTo(b10) > 0 ? a5 : b;91        return temp.compareTo(c3) > 0 ? temp10 : c;92    }
  20. System.out.println(" Max(5, 10, 3): " + maxNum);

    108Integer maxNum = MaxFinder.max(5, 10, 3);109System.out.println("  Max(5, 10, 3): " + maxNum10);
    output  Max(5, 10, 3): 10
      Max(5, 10, 3): 10
  21. temp ← zebra

    pass 2 of 2
    88class MaxFinder {89    public static <T extends Comparable<T>> T max(T aapple, T bzebra, T cbanana) {90        T temp→ zebra = a.compareTo(bzebra) > 0 ? aapple : b;91        return temp.compareTo(cbanana) > 0 ? tempzebra : c;92    }
  22. System.out.println(" Max strings: " + maxStr);

    111String maxStr = MaxFinder.max("apple", "zebra", "banana");112System.out.println("  Max strings: " + maxStrzebra);
    output  Max strings: zebra
      Max strings: zebra
  23. max ← 3.14

    94public static <T extends Comparable<T>> T maxOf(List<T> items[3.14, 2.71, 1.41, 1.73]) {95    if (items.isEmpty()) {96        return null;97    }98    T max→ 3.14 = items.get(0);99    for (T item : items) {
  24. for (T item : items)

    pass 1 of 4
    98T max = items.get(0);99for (T item3.14 : items[3.14, 2.71, 1.41, 1.73]) {100    if (item.compareTo(max) > 0) {
    All 4 passes — pass 1 is the card above
    passitem
    13.14
    22.71
    31.41
    41.73
  25. return max;

    103    }104    return max3.14;105}
  26. System.out.println(" Max double: " + maxDouble);

    115Double maxDouble = MaxFinder.maxOf(doubles);116System.out.println("  Max double: " + maxDouble3.14);117118System.out.println("\nBST node:");
    output  Max double: 3.14
      Max double: 3.14
    
    BST node:
    
    BST node:
  27. this.value ← 50

    pass 1 of 5
    125TreeNode(T value50) {126    this.value→ 50 = value50;127}
    All 5 passes — pass 1 is the card above
    passvaluethis.value
    15050
    23030
    37070
    42020
    54040
  28. root.insert(30);

    158TreeNode<Integer> root = new TreeNode<>(50);159root.insert(30);160root.insert(70);
  29. public void insert(T newValue)

    pass 1 of 6
    129public void insert(T newValue30) {130    if (newValue.compareTo(value) < 0) {
    All 6 passes — pass 1 is the card above
    passnewValueleftright
    130null
    270null
    320
    420null
    540
    640null
  30. if (newValue.compareTo(value) < 0)

    pass 1 of 4
    129public void insert(T newValue) {130    if (newValue.compareTo(value50) < 0) {131        if (left == null) {
    All 4 passes — pass 1 is the card above
    passvalueleftnewValueright
    150null
    25020
    330null
    45040null
  31. if (left == null)

    pass 1 of 2
    130if (newValue.compareTo(value) < 0) {131    if (leftnull == null) {132        left = new TreeNode<>(newValue);133        System.out.println("  Inserted left: " + newValue);
  32. left ← ⟨RecursiveBounds$1TreeNode A⟩

    131if (left == null) {132    left→ ⟨RecursiveBounds$1TreeNode A⟩ = new TreeNode<>(newValue);133    System.out.println("  Inserted left: " + newValue30);134} else {
    output  Inserted left: 30
  33. root.insert(30);

    158TreeNode<Integer> root = new TreeNode<>(50);159root.insert(30);160root.insert(70);161root.insert(20);
  34. if (right == null)

    pass 1 of 2
    137} else {138    if (rightnull == null) {139        right = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue);
  35. right ← ⟨RecursiveBounds$1TreeNode B⟩

    138if (right == null) {139    right→ ⟨RecursiveBounds$1TreeNode B⟩ = new TreeNode<>(newValue);140    System.out.println("  Inserted right: " + newValue70);141} else {
    output  Inserted right: 70
  36. root.insert(70);

    159root.insert(30);160root.insert(70);161root.insert(20);162root.insert(40);
  37. else

    pass 1 of 2
    133    System.out.println("  Inserted left: " + newValue);134} else {135    left.insert(newValue20);136}
  38. if (left == null)

    pass 2 of 2
    130if (newValue.compareTo(value) < 0) {131    if (leftnull == null) {132        left = new TreeNode<>(newValue);133        System.out.println("  Inserted left: " + newValue);
  39. left ← ⟨RecursiveBounds$1TreeNode C⟩

    131if (left == null) {132    left→ ⟨RecursiveBounds$1TreeNode C⟩ = new TreeNode<>(newValue);133    System.out.println("  Inserted left: " + newValue20);134} else {
    output  Inserted left: 20
  40. left.insert(newValue);

    134} else {135    left.insert(newValue20);136}
  41. root.insert(20);

    160root.insert(70);161root.insert(20);162root.insert(40);
  42. else

    pass 2 of 2
    133    System.out.println("  Inserted left: " + newValue);134} else {135    left.insert(newValue40);136}
  43. if (right == null)

    pass 2 of 2
    137} else {138    if (rightnull == null) {139        right = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue);
  44. right ← ⟨RecursiveBounds$1TreeNode D⟩

    134    } else {135        left.insert(newValue40);136    }137} else {138    if (right == null) {139        right→ ⟨RecursiveBounds$1TreeNode D⟩ = new TreeNode<>(newValue);140        System.out.println("  Inserted right: " + newValue40);141    } else {
    output  Inserted right: 40
  45. searchTarget ← 60

    161root.insert(20);162root.insert(40);163164int searchTarget→ 60 = 60;165System.out.println("  Contains " + searchTarget60 + ": " +166                 root.contains(searchTarget60));167System.out.println("  Contains 60: " + root.contains(60));
  46. public boolean contains(T target)

    pass 1 of 4
    147public boolean contains(T target60) {148    if (value.equals(target)) {
    All 4 passes — pass 1 is the card above
    passrightvalueleft
    1⟨RecursiveBounds$1TreeNode B⟩
    270null
    3⟨RecursiveBounds$1TreeNode B⟩
    470null
  47. else

    pass 1 of 2
    151    return left != null && left.contains(target);152} else {153    return right⟨RecursiveBounds$1TreeNode B⟩ != null && right.contains(target60);154}
  48. if (target.compareTo(value) < 0)

    pass 1 of 2
    149    return true;150} else if (target.compareTo(value70) < 0) {151    return leftnull != null && left.contains(target60);152} else {
  49. System.out.println(" Contains " + searchTarget + ": " +

    164    int searchTarget = 60;165    System.out.println("  Contains " + searchTarget60 + ": " +166                     root.contains(searchTarget60));167    System.out.println("  Contains 60: " + root.contains(60));168}
    output  Contains 60: false
  50. else

    pass 2 of 2
    151    return left != null && left.contains(target);152} else {153    return right⟨RecursiveBounds$1TreeNode B⟩ != null && right.contains(target60);154}
  51. if (target.compareTo(value) < 0)

    pass 2 of 2
    149    return true;150} else if (target.compareTo(value70) < 0) {151    return leftnull != null && left.contains(target60);152} else {
  52. System.out.println(" Contains 60: " + root.contains(60));

    166                     root.contains(searchTarget));167    System.out.println("  Contains 60: " + root.contains(60));168}
    output  Contains 60: false

<T extends Comparable<T>> - T comparable to itself. Common for sorting.

recursive bound Self-referential bound: `<T extends Comparable<T>>`. Enables self-comparison.

Bounds and inheritance

How bounded generics interact with class hierarchies.

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

public class BoundsInheritance {
    static abstract class Entity {
        private Long id;

        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
    }

    static class Repository<T extends Entity> {
        private Map<Long, T> store = new LinkedHashMap<>();
        private Long nextId = 1L;

        public void save(T entity) {
            if (entity.getId() == null) {
                entity.setId(nextId++);
            }
            store.put(entity.getId(), entity);
            System.out.println("  Saved: " + entity.getClass().getSimpleName() +
                             " id=" + entity.getId());
        }

        public T findById(Long id) {
            return store.get(id);
        }

        public List<T> findAll() {
            return new ArrayList<>(store.values());
        }

        public int count() {
            return store.size();
        }
    }

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

        class User extends Entity {
            String name;

            User(String name) {
                this.name = name;
            }

            @Override
            public String toString() {
                return "User(" + getId() + ", " + name + ")";
            }
        }

        Repository<User> userRepo = new Repository<>();

        User user1 = new User("Alice");
        User user2 = new User("Bob");

        userRepo.save(user1);
        userRepo.save(user2);

        System.out.println("  All users: " + userRepo.findAll());
        System.out.println("  Count: " + userRepo.count());

        // Bounded type allows accessing members of bound class
        // All entities have getId/setId methods
        // Type parameter must extend (or implement) the bound
        // Enables polymorphic behavior with type safety

        System.out.println("\nMultiple entity types:");

        class Product extends Entity {
            String name;
            double price;

            Product(String name, double price) {
                this.name = name;
                this.price = price;
            }

            @Override
            public String toString() {
                return "Product(" + getId() + ", " + name + ", $" + price + ")";
            }
        }

        Repository<Product> productRepo = new Repository<>();
        productRepo.save(new Product("Laptop", 999.99));
        productRepo.save(new Product("Mouse", 29.99));

        System.out.println("  All products: " + productRepo.findAll());

        System.out.println("\nService layer:");

        class Service<T extends Entity> {
            private Repository<T> repository;

            public Service(Repository<T> repository) {
                this.repository = repository;
            }

            public T create(T entity) {
                repository.save(entity);
                System.out.println("  Created: " + entity);
                return entity;
            }

            public T update(T entity) {
                if (entity.getId() == null) {
                    throw new IllegalArgumentException("Cannot update without ID");
                }
                repository.save(entity);
                System.out.println("  Updated: " + entity);
                return entity;
            }

            public T getById(Long id) {
                T entity = repository.findById(id);
                if (entity == null) {
                    System.out.println("  Not found: " + id);
                }
                return entity;
            }
        }

        Service<User> userService = new Service<>(userRepo);
        User newUser = userService.create(new User("Charlie"));
        User found = userService.getById(newUser.getId());
        System.out.println("  Retrieved: " + found);

        System.out.println("\nAuditable entities:");

        abstract class Auditable extends Entity {
            private long createdAt = 1000L;

            public long getCreatedAt() { return createdAt; }
        }

        class AuditableRepository<T extends Auditable> extends Repository<T> {
            @Override
            public void save(T entity) {
                super.save(entity);
                System.out.println("  Created at: " + entity.getCreatedAt());
            }
        }

        class Order extends Auditable {
            String product;
            int quantity;

            Order(String product, int quantity) {
                this.product = product;
                this.quantity = quantity;
            }

            @Override
            public String toString() {
                return "Order(" + getId() + ", " + product + " x" + quantity + ")";
            }
        }

        AuditableRepository<Order> orderRepo = new AuditableRepository<>();
        orderRepo.save(new Order("Laptop", 1));
        orderRepo.save(new Order("Mouse", 2));

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

        abstract class Animal {
            abstract String speak();
        }

        class Dog extends Animal {
            @Override
            String speak() { return "Woof"; }
        }

        class Cat extends Animal {
            @Override
            String speak() { return "Meow"; }
        }

        class AnimalShelter<T extends Animal> {
            private List<T> animals = new ArrayList<>();

            public void add(T animal) {
                animals.add(animal);
                System.out.println("  Added: " + animal.speak());
            }

            public void makeAllSpeak() {
                for (T animal : animals) {
                    System.out.println("  " + animal.speak());
                }
            }
        }

        AnimalShelter<Dog> dogShelter = new AnimalShelter<>();
        dogShelter.add(new Dog());
        dogShelter.add(new Dog());
        dogShelter.makeAllSpeak();
    }
}
  1. public static void main(String[] args)

    37public static void main(String[] args) {38    System.out.println("Bounds with inheritance:\n");
    outputBounds with inheritance:
    Bounds with inheritance:
  2. this.name ← Alice

    pass 1 of 3
    43User(String nameAlice) {44    this.name→ Alice = nameAlice;45}
    All 3 passes — pass 1 is the card above
    passnameentitythis.name
    1AliceAlice
    2BobBob
    3CharlieUser(null, Charlie)Charlie
  3. public Long getId()

    pass 1 of 111
    7public Long getId() { return idnull; }8public void setId(Long id) { this.id = id; }
    111 passes — pass 1 is the card above
    passidentity
    1null
    2null
    3null
    41
    51
    61
    71
    81
    91
    ⋯ 100 more passes ⋯
    1102
    1112
  4. public void save(T entity)

    pass 1 of 7
    15public void save(T entityUser(null, Alice)) {16    if (entity.getId() == null) {
    All 7 passes — pass 1 is the card above
    passentity
    1User(null, Alice)
    2User(null, Bob)
    3Product(null, Laptop, $999.99)
    4Product(null, Mouse, $29.99)
    5User(null, Charlie)
    6Order(null, Laptop x1)
    7Order(null, Mouse x2)
  5. if (entity.getId() == null)

    pass 1 of 7
    15public void save(T entity) {16    if (entity.getId() == null) {17        entity.setId(nextId1++);18    }
    All 7 passes — pass 1 is the card above
    passnextId
    11
    22
    31
    42
    53
    61
    72
  6. this.id ← 1

    pass 1 of 7
    7    public Long getId() { return id; }8    public void setId(Long id1) { this.id→ 1 = id; }9}
    All 7 passes — pass 1 is the card above
    passidthis.id
    111
    222
    311
    422
    533
    611
    722
  7. nextId ← 2

    16if (entity.getId() == null) {17    entity.setId(nextId→ 2++);18}
  8. store.put(entity.getId(), entity);

    18}19store.put(entity.getId(), entityUser(1, Alice));20System.out.println("  Saved: " + entity.getClass().getSimpleName() + 
  9. store.put(entity.getId(), entity);

    18    }19    store.put(entity.getId(), entityUser(1, Alice));20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
  10. System.out.println(" Saved: " + entity.getClass().getSimpleName() +

    19    store.put(entity.getId(), entity);20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
    output  Saved: User id=1
  11. nextId ← 3

    16if (entity.getId() == null) {17    entity.setId(nextId→ 3++);18}
  12. store.put(entity.getId(), entity);

    18}19store.put(entity.getId(), entityUser(2, Bob));20System.out.println("  Saved: " + entity.getClass().getSimpleName() + 
  13. store.put(entity.getId(), entity);

    18    }19    store.put(entity.getId(), entityUser(2, Bob));20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
  14. System.out.println(" Saved: " + entity.getClass().getSimpleName() +

    19    store.put(entity.getId(), entity);20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
    output  Saved: User id=2
  15. System.out.println(" All users: " + userRepo.findAll());

    61System.out.println("  All users: " + userRepo.findAll());62System.out.println("  Count: " + userRepo.count());
  16. System.out.println(" All users: " + userRepo.findAll());

    61System.out.println("  All users: " + userRepo.findAll());62System.out.println("  Count: " + userRepo.count());
    output  All users: [User(1, Alice), User(2, Bob)]
  17. System.out.println(" All users: " + userRepo.findAll());

    61System.out.println("  All users: " + userRepo.findAll());62System.out.println("  Count: " + userRepo.count());
    output  All users: [User(1, Alice), User(2, Bob)]
  18. System.out.println(" Count: " + userRepo.count());

    61System.out.println("  All users: " + userRepo.findAll());62System.out.println("  Count: " + userRepo.count());
    output  Count: 2
  19. System.out.println(" Count: " + userRepo.count());

    61System.out.println("  All users: " + userRepo.findAll());62System.out.println("  Count: " + userRepo.count());6364// Bounded type allows accessing members of bound class65// All entities have getId/setId methods66// Type parameter must extend (or implement) the bound67// Enables polymorphic behavior with type safety6869System.out.println("\nMultiple entity types:");
    output  Count: 2
    
    Multiple entity types:
    
    Multiple entity types:
  20. this.name ← Laptop, this.price ← 999.99

    pass 1 of 2
    75Product(String nameLaptop, double price999.99) {76    this.name→ Laptop = nameLaptop;77    this.price→ 999.99 = price999.99;78}
  21. nextId ← 2

    16if (entity.getId() == null) {17    entity.setId(nextId→ 2++);18}
  22. store.put(entity.getId(), entity);

    18}19store.put(entity.getId(), entityProduct(1, Laptop, $999.99));20System.out.println("  Saved: " + entity.getClass().getSimpleName() + 
  23. store.put(entity.getId(), entity);

    18    }19    store.put(entity.getId(), entityProduct(1, Laptop, $999.99));20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
  24. System.out.println(" Saved: " + entity.getClass().getSimpleName() +

    19    store.put(entity.getId(), entity);20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
    output  Saved: Product id=1
  25. this.name ← Mouse, this.price ← 29.99

    pass 2 of 2
    75Product(String nameMouse, double price29.99) {76    this.name→ Mouse = nameMouse;77    this.price→ 29.99 = price29.99;78}
  26. nextId ← 3

    16if (entity.getId() == null) {17    entity.setId(nextId→ 3++);18}
  27. store.put(entity.getId(), entity);

    18}19store.put(entity.getId(), entityProduct(2, Mouse, $29.99));20System.out.println("  Saved: " + entity.getClass().getSimpleName() + 
  28. store.put(entity.getId(), entity);

    18    }19    store.put(entity.getId(), entityProduct(2, Mouse, $29.99));20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
  29. System.out.println(" Saved: " + entity.getClass().getSimpleName() +

    19    store.put(entity.getId(), entity);20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
    output  Saved: Product id=2
  30. System.out.println(" All products: " + productRepo.findAll());

    90System.out.println("  All products: " + productRepo.findAll());
  31. System.out.println(" All products: " + productRepo.findAll());

    90System.out.println("  All products: " + productRepo.findAll());
    output  All products: [Product(1, Laptop, $999.99), Product(2, Mouse, $29.99)]
  32. System.out.println(" All products: " + productRepo.findAll());

    90System.out.println("  All products: " + productRepo.findAll());9192System.out.println("\nService layer:");
    output  All products: [Product(1, Laptop, $999.99), Product(2, Mouse, $29.99)]
    
    Service layer:
    
    Service layer:
  33. this.repository ← ⟨BoundsInheritance$Repository A⟩

    97public Service(Repository<T> repository⟨BoundsInheritance$Repository A⟩) {98    this.repository→ ⟨BoundsInheritance$Repository A⟩ = repository⟨BoundsInheritance$Repository A⟩;99}
  34. public T create(T entity)

    101public T create(T entityUser(null, Charlie)) {102    repository.save(entity);
  35. repository.save(entity);

    101public T create(T entity) {102    repository.save(entityUser(null, Charlie));103    System.out.println("  Created: " + entity);
  36. nextId ← 4

    16if (entity.getId() == null) {17    entity.setId(nextId→ 4++);18}
  37. store.put(entity.getId(), entity);

    18}19store.put(entity.getId(), entityUser(3, Charlie));20System.out.println("  Saved: " + entity.getClass().getSimpleName() + 
  38. store.put(entity.getId(), entity);

    18    }19    store.put(entity.getId(), entityUser(3, Charlie));20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
  39. System.out.println(" Saved: " + entity.getClass().getSimpleName() +

    19    store.put(entity.getId(), entity);20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
    output  Saved: User id=3
  40. entity ← User(3, Charlie)

    101public T create(T entity) {102    repository.save(entity→ User(3, Charlie));103    System.out.println("  Created: " + entity);
  41. System.out.println(" Created: " + entity);

    102repository.save(entity);103System.out.println("  Created: " + entityUser(3, Charlie));104return entity;
  42. System.out.println(" Created: " + entity);

    102repository.save(entity);103System.out.println("  Created: " + entityUser(3, Charlie));104return entity;
    output  Created: User(3, Charlie)
  43. return entity;

    103    System.out.println("  Created: " + entity);104    return entityUser(3, Charlie);105}
  44. public T getById(Long id)

    116public T getById(Long id3) {117    T entity = repository.findById(id3);118    if (entity == null) {
  45. public T findById(Long id)

    24public T findById(Long id3) {25    return store.get(id3);26}
  46. entity ← User(3, Charlie)

    116public T getById(Long id) {117    T entity→ User(3, Charlie) = repository.findById(id3);118    if (entity == null) {
  47. return entity;

    120    }121    return entityUser(3, Charlie);122}
  48. System.out.println(" Retrieved: " + found);

    127User found = userService.getById(newUser.getId());128System.out.println("  Retrieved: " + foundUser(3, Charlie));
  49. System.out.println(" Retrieved: " + found);

    127User found = userService.getById(newUser.getId());128System.out.println("  Retrieved: " + foundUser(3, Charlie));
    output  Retrieved: User(3, Charlie)
  50. System.out.println(" Retrieved: " + found);

    127User found = userService.getById(newUser.getId());128System.out.println("  Retrieved: " + foundUser(3, Charlie));
  51. System.out.println(" Retrieved: " + found);

    127User found = userService.getById(newUser.getId());128System.out.println("  Retrieved: " + foundUser(3, Charlie));129130System.out.println("\nAuditable entities:");
    output  Retrieved: User(3, Charlie)
    
    Auditable entities:
    
    Auditable entities:
  52. this.product ← Laptop, this.quantity ← 1

    pass 1 of 2
    150Order(String productLaptop, int quantity1) {151    this.product→ Laptop = productLaptop;152    this.quantity→ 1 = quantity1;153}
  53. @Override public void save(T entity)

    pass 1 of 2
    138class AuditableRepository<T extends Auditable> extends Repository<T> {139    @Override140    public void save(T entityOrder(null, Laptop x1)) {141        super.save(entity);
  54. super.save(entity);

    140public void save(T entity) {141    super.save(entityOrder(null, Laptop x1));142    System.out.println("  Created at: " + entity.getCreatedAt());
  55. nextId ← 2

    16if (entity.getId() == null) {17    entity.setId(nextId→ 2++);18}
  56. store.put(entity.getId(), entity);

    18}19store.put(entity.getId(), entityOrder(1, Laptop x1));20System.out.println("  Saved: " + entity.getClass().getSimpleName() + 
  57. store.put(entity.getId(), entity);

    18    }19    store.put(entity.getId(), entityOrder(1, Laptop x1));20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
  58. System.out.println(" Saved: " + entity.getClass().getSimpleName() +

    19    store.put(entity.getId(), entity);20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
    output  Saved: Order id=1
  59. entity ← Order(1, Laptop x1)

    140public void save(T entity) {141    super.save(entity→ Order(1, Laptop x1));142    System.out.println("  Created at: " + entity.getCreatedAt());143}
  60. public long getCreatedAt()

    pass 1 of 2
    135    public long getCreatedAt() { return createdAt1000; }136}
  61. System.out.println(" Created at: " + entity.getCreatedAt());

    141    super.save(entity);142    System.out.println("  Created at: " + entity.getCreatedAt());143}
    output  Created at: 1000
  62. this.product ← Mouse, this.quantity ← 2

    pass 2 of 2
    150Order(String productMouse, int quantity2) {151    this.product→ Mouse = productMouse;152    this.quantity→ 2 = quantity2;153}
  63. @Override public void save(T entity)

    pass 2 of 2
    138class AuditableRepository<T extends Auditable> extends Repository<T> {139    @Override140    public void save(T entityOrder(null, Mouse x2)) {141        super.save(entity);
  64. super.save(entity);

    140public void save(T entity) {141    super.save(entityOrder(null, Mouse x2));142    System.out.println("  Created at: " + entity.getCreatedAt());
  65. nextId ← 3

    16if (entity.getId() == null) {17    entity.setId(nextId→ 3++);18}
  66. store.put(entity.getId(), entity);

    18}19store.put(entity.getId(), entityOrder(2, Mouse x2));20System.out.println("  Saved: " + entity.getClass().getSimpleName() + 
  67. store.put(entity.getId(), entity);

    18    }19    store.put(entity.getId(), entityOrder(2, Mouse x2));20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
  68. System.out.println(" Saved: " + entity.getClass().getSimpleName() +

    19    store.put(entity.getId(), entity);20    System.out.println("  Saved: " + entity.getClass().getSimpleName() + 21                     " id=" + entity.getId());22}
    output  Saved: Order id=2
  69. entity ← Order(2, Mouse x2)

    140public void save(T entity) {141    super.save(entity→ Order(2, Mouse x2));142    System.out.println("  Created at: " + entity.getCreatedAt());143}
  70. public long getCreatedAt()

    pass 2 of 2
    135    public long getCreatedAt() { return createdAt1000; }136}
  71. System.out.println(" Created at: " + entity.getCreatedAt());

    141    super.save(entity);142    System.out.println("  Created at: " + entity.getCreatedAt());143}
    output  Created at: 1000
  72. System.out.println(" Type hierarchy:");

    165System.out.println("\nType hierarchy:");166167abstract class Animal {168    abstract String speak();169}170171class Dog extends Animal {172    @Override173    String speak() { return "Woof"; }174}175176class Cat extends Animal {177    @Override178    String speak() { return "Meow"; }179}180181class AnimalShelter<T extends Animal> {182    private List<T> animals = new ArrayList<>();183    184    public void add(T animal) {185        animals.add(animal);186        System.out.println("  Added: " + animal.speak());187    }188    189    public void makeAllSpeak() {190        for (T animal : animals) {191            System.out.println("  " + animal.speak());192        }193    }194}195196AnimalShelter<Dog> dogShelter = new AnimalShelter<>();197dogShelter.add(new Dog());198dogShelter.add(new Dog());
    output
    Type hierarchy:
    
    Type hierarchy:
  73. public void add(T animal)

    pass 1 of 2
    184public void add(T animal⟨BoundsInheritance$1Dog B⟩) {185    animals.add(animal⟨BoundsInheritance$1Dog B⟩);186    System.out.println("  Added: " + animal.speak());187}
  74. System.out.println(" Added: " + animal.speak());

    185    animals.add(animal);186    System.out.println("  Added: " + animal.speak());187}
    output  Added: Woof
  75. dogShelter.add(new Dog());

    196AnimalShelter<Dog> dogShelter = new AnimalShelter<>();197dogShelter.add(new Dog());198dogShelter.add(new Dog());199dogShelter.makeAllSpeak();
  76. public void add(T animal)

    pass 2 of 2
    184public void add(T animal⟨BoundsInheritance$1Dog C⟩) {185    animals.add(animal⟨BoundsInheritance$1Dog C⟩);186    System.out.println("  Added: " + animal.speak());187}
  77. System.out.println(" Added: " + animal.speak());

    185    animals.add(animal);186    System.out.println("  Added: " + animal.speak());187}
    output  Added: Woof
  78. dogShelter.add(new Dog());

    197    dogShelter.add(new Dog());198    dogShelter.add(new Dog());199    dogShelter.makeAllSpeak();200}
  79. for (T animal : animals)

    pass 1 of 2
    189public void makeAllSpeak() {190    for (T animal⟨BoundsInheritance$1Dog B⟩ : animals⟨BoundsInheritance$1Dog[] B⟩, ⟨BoundsInheritance$1Dog C⟩]) {191        System.out.println("  " + animal.speak());192    }
  80. System.out.println(" " + animal.speak());

    190for (T animal : animals) {191    System.out.println("  " + animal.speak());192}
    output  Woof
  81. for (T animal : animals)

    pass 2 of 2
    189public void makeAllSpeak() {190    for (T animal⟨BoundsInheritance$1Dog C⟩ : animals⟨BoundsInheritance$1Dog[] B⟩, ⟨BoundsInheritance$1Dog C⟩]) {191        System.out.println("  " + animal.speak());192    }
  82. System.out.println(" " + animal.speak());

    190for (T animal : animals) {191    System.out.println("  " + animal.speak());192}
    output  Woof
  83. dogShelter.makeAllSpeak();

    198    dogShelter.add(new Dog());199    dogShelter.makeAllSpeak();200}

Subclasses satisfy superclass bounds. Integer extends Number satisfies <T extends Number>.

Exercise: Practical.java

Build a bounded generic collection for numbers