1 of 22

Discussion 4: Inheritance

2 of 22

Administrivia

  • Project 1Gold released, due Saturday 2/16
  • Project 1B released, due Saturday 2/16
  • Sign up for CSM sections ASAP
  • One-on-one tutoring sign-ups on Piazza weekly
  • Discussion/Lab Changes:
    • Disc 150 - Now Reg Disc, taught by Carlo
    • Lab 129 - Now Challenge Lab, taught by Danny
    • Lab 133 - Reg Lab, taught by Eli
    • Lab 145 - Challenge Lab, taught by Itai

3 of 22

Inheritance

public class Fish {

int weight;

public Fish(int w) {

weight = w;

}

public void swim() {

System.out.println(“splash”);

}

}

public class Salmon extends Fish {

String home;

public Salmon(int w, String h) {

super(w);

home = h;

}

public void migrate() {

System.out.println(“Migrating to ” + home);

}

}

Superclass

Subclass

Salmon inherits these from Fish

This invokes the super class’s constructor

4 of 22

Static vs Dynamic type: what fits in the box?

Fish fish1 = new Fish();

Fish fish2 = new Salmon();

Salmon salmon1 = new Salmon();

Salmon salmon2 = new Fish();

Salmon salmon3 = fish2;

Static type

Dynamic type

Static Type:

Salmon

Fish

5 of 22

Overriding/Overloading

public class Salmon extends Fish {

String home;

public Salmon(int w, String h) {

super(w);

home = h;

}

public void swim() {

System.out.println(“splish splash”);

}

public void swim(int speed) {

System.out.println(“swimming at “ + speed + “ mph”);

}

}

public class Fish {

int weight;

public Fish(int w) {

weight = w;

}

public void swim() {

System.out.println(“splash”);

}

}

Overriding: exact same method signature

Overloading: same name, different parameters

6 of 22

Dynamic Method Selection

Fish fish = new Fish();

Salmon salmon = new Salmon();

Fish bob = new Salmon();

fish.swim();

salmon.swim();

bob.swim();

fish.swim(5);

salmon.swim(5);

bob.swim(5)

Compile time: static method lookup

Run time: dynamic method lookup

7 of 22

Dynamic Method Selection

Fish fish = new Fish();

Salmon salmon = new Salmon();

Fish bob = new Salmon();

fish.swim();

salmon.swim();

bob.swim();

fish.swim(5);

salmon.swim(5);

bob.swim(5)

splash

splish splash

splish splash

compile-time error

swimming at 5 mph

compile-time error

Compile time: static method lookup

Run time: dynamic method lookup

8 of 22

Casting

Fish redFish = new Fish();

Fish blueFish = new Salmon();

blueFish.swim(5); /* This wouldn’t compile before */

((Salmon) blueFish).swim(5); /* Now it does! */

((Salmon) redFish).swim(5); /* This compiles but gives you a runtime error (ClassCastException) */

9 of 22

Interfaces

public interface Plant {

public void grow();

public void photosynthesize();

}

public class Rose implements Plant {

public int height;

public void grow() { height += 1; }

public void photosynthesize() {

System.out.println(“Rose feels energized!”);

}

}

Rose promises to provide implementations of all of Plant’s abstract methods

Plant plant = new Rose();

Plant plant = new Plant();

10 of 22

JUnit Tests

@Test

public void testdSquareList() {

IntList L = IntList.list(1, 2, 3);

IntList.dSquareList(L);

assertEquals(IntList.list(1, 4, 9), L);

}

@Test

public void testList() {

IntList one = new IntList(1, null);

IntList twoOne = new IntList(2, one);

IntList threeTwoOne = new IntList(3, twoOne);

IntList x = IntList.list(3, 2, 1);

assertEquals(threeTwoOne, x);

}

11 of 22

JUnit Tests

Disadvantages

  • Complex High level Testing

Advantages

  • Organized code
  • Easy debugging
  • Code reusability
  • Validates code

12 of 22

Creating Cats

  • What will Cat inherit from Animal?
  • How can we rewrite as little code as possible?

13 of 22

Creating Cats

public class Cat extends Animal {

public Cat(String name, int age) {

super(name, age); // Call superclass' constructor.

this.noise = "Meow!"; // Change the value of the field.

}

@Override

public void greet() {

System.out.println("Cat " + name + " says: " + makeNoise());

}

}

14 of 22

Raining Cats and Dogs

  • Remember dynamic method lookup for overridden methods
  • Casting forces the compile-time type of an object

johnsu.deviantart.com/art/Raining-Cats-and-Dogs-30291521

15 of 22

Raining Cats and Dogs

Animal a = new Animal("Pluto", 10);

Cat c = new Cat("Garfield", 6);

Dog d = new Dog("Fido", 4);

a.greet(); // (A) Animal Pluto says: Huh?

c.greet(); // (B) Cat Garfield says: Meow!

d.greet(); // (C) Dog Fido says: WOOF!

a = c;

((Cat) a).greet(); // (D) Cat Garfield says: Meow!

a.greet(); // (E) Cat Garfield says: Meow!

16 of 22

What if we added this line?

Animal a = new Animal("Pluto", 10);

Dog d = new Dog("Fido", 4);

a = new Dog("Spot", 10);

d = a;

Compiler error because the static type of d is Dog and the static type of a is Animal. We can fix this by casting:

d = (Dog) a;

17 of 22

An Exercise in Inheritance Misery (Extra)

class C extends B {

public int y = x + 1;

public void m2() {System.out.println("Cm2-> " + super.x);}

/*public void m4() {System.out.println("Cm4-> " + super.super.x); }} can't do super.super */

public void m5() {System.out.println("Cm5-> " + y);}

}

18 of 22

An Exercise in Inheritance Mystery (Extra)

\\ B a0 = new A(); Dynamic type must be B or subclass of B

\\ a0.m1(); cascading: prev line failed, so a0 can't be initialized

\\ a0.m2(16); cascading: prev line failed, so a0 can't be initialized

19 of 22

An Exercise in Inheritance Mystery (Extra)

A b0 = new B();

System.out.println(b0.x); [prints "5"]

b0.m1(); [prints "Am1-> 5"]

b0.m2(); [prints "Bm2-> 5"]

\\ b0.m2(61); m2 (int y) not defined in static type of b0

20 of 22

An Exercise in Inheritance Mystery (Extra)

B b1 = new B();

b1.m2(61); [prints "Bm2y-> 61"]

b1.m3(); [prints "Bm3-> called"]

A c0 = new C();

c0.m2(); [prints "cm2-> 5"]

\\ C c1 = (A) new C(); Can't assign c1 to an A

21 of 22

An Exercise in Inheritance Mystery (Extra)

A c0 = new C();

A b0 = new B();

((C) c0).m3(); [print Bm3-> called]

\\ (C) c0.m3(); A bunch of errors in this one… Compile Time: you can’t cast a void return value

b0.update();

b0.m1(); [print Am1-> 99]

22 of 22

An Exercise in Inheritance Mystery (Extra)

A c0 = new C();

A a1 = (A) c0;

C c2 = (C) a1;

c2.m3(); [print Bm3-> called]

\\ c2.m4(); C.m4() is invalid

c2.m5(); [print Cm5-> 6]