CSE 331�Software Design & Implementation
Spring 2026
Section 8 – HW 6 Demo, Subtypes & Generics
Administrivia
HW 6 Demo
Subtypes
Strength
class Pony {...}
class Unicorn extends Pony {...}
* not enforced by Java, but very important practice to only define subclasses that are also subtypes!
Type Bounds
Upper Bound: extends
Lower Bound: super
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
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
Type Constraints on Methods
Code can only use methods from type bounds
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
Generics
Throughout this entire class we’ve been dealing with Lists of numbers, booleans, and pairs
What if we wanted to create a definition for any list?
type List<A> := nil | cons(x: A, L: List<A>)
Ex:
class FastLastList<T> implements List<T> {
private List<T> list;
private T last;
}
Generic Methods
Ex: Summing a List of integers or doubles:
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;
}
Wildcards: ?
?: Concise way of writing some generics
? vs Object:
T vs ?
Ex:
Both of these functions are equivalent:
If you want both lists to have the same type, you must use T:
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.
Object obj;
Game game;
List<Game> games;
CardGame cardGame;
List<? extends CardGame> cardGames;
VideoGame videoGame; List<VideoGame> videoGames;
GoFish goFish;
List<? super GoFish> goFishGames;
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.
This is illegal since Object is not a subclass of any subclass of CardGame. (Object is a superclass of CardGame)
This is illegal since Object is not a subclass of VideoGame.
This is illegal since our list may be of type i.e., List<Game> and Object cannot be cast down into a game.
This is legal since goFish is castable into any of its superclasses.
Object obj;
Game game;
List<Game> games;
CardGame cardGame;
List<? extends CardGame> cardGames;
VideoGame videoGame; List<VideoGame> videoGames;
GoFish goFish;
List<? super GoFish> goFishGames;
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.
e) cardGames.add(cardGame);
This is illegal since cardGames could be, e.g., List<GoFish>, and CardGame is not a subclass of GoFish.
f) goFishGames.add(null);
This is legal.
g) cardGame = cardGames.get(0);
This is legal since anything extending CardGame is castable to it.
h) videoGame = videoGames.get(0);
This is legal.
Object obj;
Game game;
List<Game> games;
CardGame cardGame;
List<? extends CardGame> cardGames;
VideoGame videoGame; List<VideoGame> videoGames;
GoFish goFish;
List<? super GoFish> goFishGames;
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.
i) goFish = goFishGames.get(0);
This is illegal since goFishGames could be, e.g., List<Object>.
j) obj = goFishGames.get(0);
This is legal since anything is castable to Object.
k) goFish = cardGames.get(0);
This is illegal since cardGames could be, e.g., a CardGame.
Object obj;
Game game;
List<Game> games;
CardGame cardGame;
List<? extends CardGame> cardGames;
VideoGame videoGame; List<VideoGame> videoGames;
GoFish goFish;
List<? super GoFish> goFishGames;
Generic Method Declarations
Strength rules:
Generics Control Strength
When comparing declarations, ask:
If yes, it is stronger. (weaker precondition)
Guidelines:
If neither allows strictly more calls or has stronger guarantees → incomparable
Task 2 – A Compare To Remember
Answer each of the following questions about generic method declarations.
The first two parts use the type Comparable<T>, which is an interface containing only one method:
int compareTo(T other)
This function compares the object on which it is called, obj, and the passed-in object other. It returns -1 to indicate that obj comes before other, +1 to indicate that obj comes after other, and 0 if they can be placed in either order. (311 alert: the "before" relationship must be transitive, reflexive, and anti-symmetric.)
Task 2 – A Compare To Remember
Answer each of the following questions about generic method declarations.
The first two parts use the type Comparable<T>, which is an interface containing only one method:
int compareTo(T other)
This function compares the object on which it is called, obj, and the passed-in object other. It returns -1 to indicate that obj comes before other, +1 to indicate that obj comes after other, and 0 if they can be placed in either order. (311 alert: the "before" relationship must be transitive, reflexive, and anti-symmetric.)
A: <E extends Comparable<E>> void randomize(Collection<E> vals)
B: <E extends Comparable<E>> void randomize(List<E> vals)
C: <E extends Comparable<? extends E>> void randomize(Collection<E> vals)
D: <E extends Comparable<? super E>> void randomize(List<E> vals)
Task 2 – A Compare To Remember
Answer each of the following questions about generic method declarations.
A: <E extends Comparable<E>> void randomize(Collection<E> vals)
B: <E extends Comparable<E>> void randomize(List<E> vals)
C: <E extends Comparable<? extends E>> void randomize(Collection<E> vals)
D: <E extends Comparable<? super E>> void randomize(List<E> vals)
a) Is A stronger, weaker, or incomparable to B? Briefly explain your answer:
A is stronger because it accepts Collections of any type, whereas you can only provide Lists of any type to B.
b) Is A stronger, weaker, or incomparable to C? Briefly explain your answer:
A is weaker because it only accepts types that are Comparable with themselves. Meanwhile, C accepts types that are Comparable with themselves or any subclasses
c) Is B stronger, weaker, or incomparable to D? Briefly explain your answer:
B is weaker because it only accepts types that are Comparable with themselves. Meanwhile, D accepts types that are Comparable with themselves or any superclass
d) Is C stronger, weaker, or incomparable to D? Briefly explain your answer:
C is incomparable because it’s not possible to compare the set of superclasses and subclasses with one another.
Task 2 – A Compare To Remember
Answer each of the following questions about generic method declarations.
The first two parts use the type Comparable<T>, which is an interface containing only one method:
int compareTo(T other)
This function compares the object on which it is called, obj, and the passed-in object other. It returns -1 to indicate that obj comes before other, +1 to indicate that obj comes after other, and 0 if they can be placed in either order. (311 alert: the "before" relationship must be transitive, reflexive, and anti-symmetric.)
b) The following type declaration is legal, but probably does not make sense. Why not? Collection<? extends Comparable<?>>
This allows a collection of one type of object that are comparable to a different type of object. That means you can't actually compare elements of the collection to each other, e.g., for the purposes of sorting.
Task 2 – A Compare To Remember
Answer each of the following questions about generic method declarations.
c) 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:
A is stronger because it accepts Collections of any type, whereas you can only provide Collections of Objects to B.
b) Is A stronger, weaker, or incomparable to C? Briefly explain your answer:
A is stronger because it accepts two Collections which can each have any type, whereas both Collections in C must have the same type.
c) Is B stronger, weaker, or incomparable to C? Briefly explain your answer:
B is weaker because it accepts two Collections of Objects, whereas C’s Collections can have any type.
d) Is C stronger, weaker, or incomparable to D? Briefly explain your answer:
C is weaker because its Collections must have the same type, whereas D’s sub Collection can have any type at or below T, and list can have any type at or above T.
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(obj) != 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.
The parameter types for contains, add, and remove should be changed. The return type for max should be changed. The type parameter for the returned list in getSetAsListForTestingDoNotCallOrElse should be changed to List<T>.
The int return type in size should NOT be changed!
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(obj) != 0
* @return the largest integer in the set
*/
public int max();
b) What bounds should we put on T?
Because of the max() method, it should be extends Comparable<T> (or even more general, extends Comparable<? super T>).
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.
import java.util.List;
public interface MutableSet<T extends Comparable<T>> {
public boolean contains(T n);
public void add(T n);
public boolean remove(T n);
public int size();
public T max();
}
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?
The main interface description is specific to integers; it should be changed to say elements. Several @param and @return descriptions specify "number" or "int" (e.g., in remove), which should be updated to "element." Lastly, the specification of max needs to clarify that "largest" is determined by calling compareTo() rather than a mathematical comparison operator.