CSE 331: Software Design and Implementation, Autumn 2026
Your job is to deliver code that you know works.
$ javac Products.java Products.java:17: error: incompatible types: String cannot be converted to Product cart.add("skittles"); ^ ⋮ 1 error
cart is a List<Product>, so add expects a Product: a String is refused36class Product {
37 private String name;
38 private double price;63class SaleProduct extends Product {
64 private double discount; // the fraction taken off, 0 to 116List<Product> cart = new ArrayList<>();
17cart.add(new Product("skittles", 2.0));
18cart.add(new SaleProduct("m&ms", 2.0, 0.5));15public static void main(String[] args) {
16 List<Product> cart = new ArrayList<>();
17 cart.add(new Product("skittles", 2.0));
18 cart.add(new SaleProduct("m&ms", 2.0, 0.5));
19 for (Product p : cart) {
20 System.out.println(p);
21 }
22 System.out.println("total: $" + total(cart));
23}55/** @return this product's name and price, as "name: $price" */
56@Override
57public String toString() {
58 return name + ": $" + price;
59}74 */
75@Override
76public double getPrice() {
77 return super.getPrice() * (1 - discount);
78}$ java Products skittles: $2.0 m&ms: $2.0 total: $3.0
add compiled: a SaleProduct went as a Producttotal called getPrice, and SaleProduct's ranDefinition: Java subtype
A type B is a Java subtype of a type A if the compiler accepts a B where an A is expected.
The compiler accepts it when B reaches A by a chain of extends and implements.
36class Product {63class SaleProduct extends Product {17cart.add(new Product("skittles", 2.0));
18cart.add(new SaleProduct("m&ms", 2.0, 0.5));add is allowed: SaleProduct extends Product directlyDefinition: Subclassing
class B extends A makes B a subclass of A. B inherits A's fields and
methods: it has them without writing them out, except the methods it overrides.
55/** @return this product's name and price, as "name: $price" */
56@Override
57public String toString() {
58 return name + ": $" + price;
59}26public static double total(List<Product> cart) {
27 double sum = 0.0;
28 for (Product p : cart) {
29 sum = sum + p.getPrice();
30 }
31 return sum;
32}extends, inheritance and Java subtyping at oncetotal never read SaleProduct's code, so what did it rely on?total was argued correct against Product, and a SaleProduct arrivedtotal never read SaleProduct's code, and could not havetotal's argument right?48
49/** Finds a value in an array, if it is there. */
50interface Finder {
51 /**
52 * @return the smallest index i such that a[i] == x, or -1 if x
53 * does not occur in a
54 */
55 int indexOf(int[] a, int x);
56}58/** Finds a value known to be in an array. */
59interface PresentFinder extends Finder {
60 /**
61 * @requires x occurs in a
62 * @return the smallest index i such that a[i] == x
63 */
64 int indexOf(int[] a, int x);
65}16public static boolean contains(Finder finder, int[] a, int x) {
17 return finder.indexOf(a, x) != -1;
18}contains(assuming, a, 7) if 7 is not in the array?Definition: Behavioral subtype
A type B is a behavioral subtype of a type A if: every object that satisfies B's specification also satisfies A's. In other words: for each method of A, that method exists in B, and the B version's specification is at least as strong as the A version's.
$ java IndexOf 3 in a: true 7 in a: false 3 in a: true Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4 at ScanAssuming.indexOf(IndexOf.java:83) at IndexOf.contains(IndexOf.java:17) at IndexOf.main(IndexOf.java:27)
contains is right for every FinderextendsBarbara Liskov, "Data Abstraction and Hierarchy", 1987; Liskov and Wing, 1994.
21interface Source {
22 /**
23 * @return a list of the indexes at which x occurs in this
24 * sequence, in increasing order
25 * @throws IOException if the numbers could not be read
26 */
27 List<Integer> positions(int x) throws IOException;
28}30/** A sequence of numbers kept in an array in memory. */
31interface ArraySource extends Source {
32 /**
33 * @return a new ArrayList of the indexes at which x occurs in
34 * this sequence, in increasing order
35 */
36 ArrayList<Integer> positions(int x);
37}javac checks an override's return type: the same or a subtypeRule: declare only behavioral subtypes
Only declare Java subtypes that are actually behavioral subtypes.
14/**
15 * @modifies r
16 * @effects sets r's width to w; r's height is unchanged
17 * @return the area of r afterward
18 */
19public static int widen(Rectangle r, int w) {
20 int h = r.getHeight();
21 r.setWidth(w);
22 return w * h;
23}82/**
83 * @modifies this
84 * @effects sets this square's width and height to w
85 */
86@Override
87public void setWidth(int w) {
88 super.setWidth(w);
89 super.setHeight(w);
90}class Square extends Rectanglemain widens a 2 by 3 rectangle, then a 2 by 2 square, to width 5widen returned, and the area afterward57/**
58 * @modifies this
59 * @effects sets this rectangle's width to w; its height is
60 * unchanged
61 */
62public void setWidth(int w) {
63 width = w;
64}82/**
83 * @modifies this
84 * @effects sets this square's width and height to w
85 */
86@Override
87public void setWidth(int w) {
88 super.setWidth(w);
89 super.setHeight(w);
90}extends Rectangle breaks the rule; the is-a test is not the test49/**
50 * @return a new rectangle whose width is w and whose height is
51 * this rectangle's height
52 */
53public Rectangle withWidth(int w) {
54 return new Rectangle(w, height);
55}96/**
97 * @modifies this
98 * @effects sets this square's width and height to s
99 */
100public void setSide(int s) {
101 rect.setWidth(s);
102 rect.setHeight(s);
103}withWidth returns a new Rectanglewiden(s) is refused