1 of 19

CSE 331�Software Design & Implementation

Spring 2026

Section 7 – Generics

2 of 19

Administrivia

  • HW++ released Friday- �Due @ 11:59pm next Friday

3 of 19

Type Bounds

Upper Bound: extends

  • Type argument passed in must be the same type or a subclass

Lower Bound: super

  • Type argument passed in must be the same type or a superclass

4 of 19

Type Constraints: Extends

Ex:

List<? extends Unicorn> unicorns = new ArrayList<Unicorn>()

unicorns = new ArrayList<Rarity> // okay!

unicorns = new ArrayList<RainbowDash> // error!

Pony

RainbowDash

Unicorn

Rarity

5 of 19

Type Constraints: Super

Ex:

List<? super Unicorn> ponies = new Arraylist<Pony>()

ponies = new ArrayList<Rarity> // error!

ponies = new ArrayList<Pony> // ok!

Pony

RainbowDash

Unicorn

Rarity

6 of 19

Type Constraints on Methods

Code can only use methods from type bounds

  • Can only call methods guaranteed to be there

Ex:

class PinkyPie<E extends Pony>{

public string magic(E arg) {

return arg.magic(); // error! (Pony not guaranteed to magic())

}

}

class Twilight<E extends Unicorn>{

public string magic(E arg) {

return arg.magic(); // okay! (Unicorn is guaranteed to magic())

}

}

Pony

RainbowDash

Unicorn

Rarity

7 of 19

Task 1 – We Game To Please

class Game {..}

class CardGame extends Game {..}

class VideoGame extends Game {..}

class GoFish extends CardGame {..}

For each line of code below, state whether the call is legal or illegal. If it is illegal, briefly explain why.

  1. cardGames.add(this);
  2. videoGames.add(this);
  3. goFishGames.add(this);
  4. goFishGames.add(goFish);
  5. cardGames.add(cardGame);
  6. goFishGames.add(null);
  7. cardGame = cardGames.get(0);
  8. videoGame = videoGames.get(0);
  9. goFish = goFishGames.get(0);
  10. this = goFishGames.get(0);
  11. goFish = cardGames.get(0);

Object this;

Game game; List<Game> games;

CardGame cardGame; List<? extends CardGame> cardGames;

VideoGame videoGame; List<VideoGame> videoGames;

GoFish goFish; List<? super GoFish> goFishGames;

8 of 19

Generics

class MySet<T> { // generic class

private List<T> list;

private T lastAccessed;

}�

// generic method

static <T extends Number> double sum(List<T> list) {

double result = 0;

for (T n : list) {

result += n.doubleValue(); // Legal since T extends Number

}

return result;

}

9 of 19

Wildcards: ?

?: Concise way of writing some generics

  • Used to represent an unknown type - is unnamed
  • ? extends E”: ? is an anonymous subclass of E
  • ? super E”: ? is an anonymous superclass of E
  • ?” is an anonymous subclass of Object
  • Each “?” is independent from each other
  • Allows for flexible input types

? vs Object:

  • List<?> allows for Object, but also Integer, String, etc…
  • Cannot pass List<Integer> for List<Object>
  • Can pass List<Integer> as List<?>

10 of 19

Generics: T vs ?

  • Use T to explicitly define, control, and reuse a given type
  • Use ? for dynamic, non-reusable input types where you don’t need to know the exact type
  • You can return T, but you cannot return ?

Ex:

Both of these functions are equivalent:

  • <T1, T2> void foo(List<T1> list, List<T2> list2) {...}
  • void foo(List<?> list, List<?> list2) {...}

If you want both lists to have the same type, you must use T:

  • <T> void foo(List<T> list, List<T> list2) {...}

11 of 19

Generic Method Declarations

  • We can compare generic method declarations similarly to how we compare specifications:

    • Parameters = preconditions
    • Return types = postconditions

Strength rules:

  • A method is stronger if:
    • it accepts more argument types (weaker precondition)
    • it returns a more specific type (stronger postcondition)
  • A method is weaker if:
    • it accepts fewer argument types (stronger precondition)
    • it returns a less specific type (weaker postcondition)

12 of 19

Generics Control Strength

When comparing declarations, ask:

  • Which accepts more possible argument types?
  • Which enforces weaker type relationships?
  • Does one strictly accept more valid calls than the other?

If yes, it is stronger. (weaker precondition)

Guidelines:

  • extends → widens acceptable inputs → weaker precondition → stronger method
  • super→ widens acceptable inputs → weaker precondition → stronger method
  • <T> → ties types together → stronger type relationship
  • ? → each ? is independent → weaker type relationship

If neither allows strictly more calls or has stronger guarantees → incomparable

13 of 19

Task 2 – A Compare To Remember

Answer each of the following questions about generic method declarations.

a) Consider the following alternative method declarations:

A: int find(Collection<?> sub, Collection<?> list)

B: int find(Collection<Object> sub, Collection<Object> list)

C: <T> int find(Collection<T> sub, Collection<T> list)

D: <T> int find(Collection<? extends T> sub, Collection<? super T> list)

a) Is A stronger, weaker, or incomparable to B? Briefly explain your answer:

b) Is A stronger, weaker, or incomparable to C? Briefly explain your answer:

c) Is B stronger, weaker, or incomparable to C? Briefly explain your answer:

d) Is C stronger, weaker, or incomparable to D? Briefly explain your answer:

14 of 19

Task 2 – A Compare To Remember

b) The following type declaration is legal, but probably does not make sense. Why not? Collection<? extends Comparable<?>>

15 of 19

Task 3 – Nothing Is Certain But Death and Maxes

Revisit the specification of MutableIntSet. We are adding a max operation to the ADT that finds the largest element in the set.

/**

* Returns the largest value in the set, which must be non-empty.

* @requires len(this) != 0

* @return the largest integer in the set

*/

public int max();

In this problem, we will change the interface to store data other than integers by introducing a type parameter T for the type of data stored in the set.

  1. Find all the places where "int" (or "Integer") appears in your interface. Which of these should be replaced by T's?

16 of 19

Task 3 – Nothing Is Certain But Death and Maxes

Revisit the specification of MutableIntSet. We are adding a max operation to the ADT that finds the largest element in the set.

/**

* Returns the largest value in the set, which must be non-empty.

* @requires len(this) != 0

* @return the largest integer in the set

*/

public int max();

b) What bounds should we put on T?

17 of 19

Task 3 – Nothing Is Certain But Death and Maxes

Revisit the specification of MutableIntSet. We are adding a max operation to the ADT that finds the largest element in the set.

c) Next, we will make the change. Make MutableIntSet into a generic interface MutableSet that can store other types of data.

18 of 19

Task 3 – Nothing Is Certain But Death and Maxes

Revisit the specification of MutableIntSet. We are adding a max operation to the ADT that finds the largest element in the set.

d) Do the documentation/specifications still make sense? If not, what do we need to fix?

19 of 19

End

Please turn in your half-sheets!