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!