Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 11

Exercise 11: Add class Pickle to Sandwich.java.

package polymorphism;

class Meal {
    Meal() {
        System.out.println("Meal()");
    }
}

class Bread {
    Bread() {
        System.out.println("Bread()");
    }
}

class Cheese {
    Cheese() {
        System.out.println("Cheese()");
    }
}

class Lettuce {
    Lettuce() {
        System.out.println("Lettuce()");
    }
}

class Pickle {
    Pickle() {
        System.out.println("Pickle()");
    }
}

class Lunch extends Meal {
    Lunch() {
        System.out.println("Lunch()");
    }
}

class PortableLunch extends Lunch {
    PortableLunch() {
        System.out.println("PortableLunch()");
    }
}

public class Sandwich11 extends PortableLunch {
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Pickle p = new Pickle();
    private Lunch l = new Lunch();

    public Sandwich11() {
        System.out.println("Sandwich()");
    }

    public static void main(String[] args) {
        new Sandwich11();
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 10

Exercise 10: Create a base class with two methods. In the first method, call the second method. Inherit a class and override the second method. Create an object of the derived class, upcast it to the base type, and call the first method. Explain what happens.

class A {
    protected void f() {
        System.out.println("A.f()");
        this.g();
    }

    protected void g() {
        System.out.println("A.g()");
    }
}

class B extends A {
    @Override
    protected void g() {
        System.out.println("B.g()");
    }
}

public class Ex10 {
    public static void main(String[] args) {
        B b = new B();
        // automatic upgrade to base-class to call base-class method A.f()
        // which,by polymorphism, will call the derived-class method B.g():
        b.f();
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 9

Exercise 9: Create an inheritance hierarchy of Rodent: Mouse, Gerbil, Hamster, etc. In the base class, provide methods that are common to all Rodents, and override these in the derived classes to perform different behaviors depending on the specific type of Rodent. Create an array of Rodent, fill it with different specific types of Rodents, and call your base-class methods to see what happens.

package polymorphism.rodent;

import java.util.*;

public class RandomRodentGenerator {
    private Random rand = new Random();

    public Rodent next() {
        switch (rand.nextInt(3)) {
        default:
        case 0:
            return new Mouse();
        case 1:
            return new Rat();
        case 2:
            return new Squirrel();
        }
    }
}
package polymorphism.rodent;

class Rodent {
    private String name = "Rodent";

    protected void eat() {
        System.out.println("Rodent.eat()");
    }

    protected void run() {
        System.out.println("Rodent.run()");
    }

    protected void sleep() {
        System.out.println("Rodent.sleep()");
    }

    public String toString() {
        return name;
    }
}

class Mouse extends Rodent {
    private String name = "Mouse";

    protected void eat() {
        System.out.println("Mouse.eat()");
    }

    protected void run() {
        System.out.println("Mouse.run()");
    }

    protected void sleep() {
        System.out.println("Mouse.sleep()");
    }

    public String toString() {
        return name;
    }
}

class Rat extends Rodent {
    private String name = "Rat";

    protected void eat() {
        System.out.println("Rat.eat()");
    }

    protected void run() {
        System.out.println("Rat.run()");
    }

    protected void sleep() {
        System.out.println("Rat.sleep()");
    }

    public String toString() {
        return name;
    }
}

class Squirrel extends Rodent {
    private String name = "Squirrel";

    protected void eat() {
        System.out.println("Squirrel.eat()");
    }

    protected void run() {
        System.out.println("Squirrel.run()");
    }

    protected void sleep() {
        System.out.println("Squirrel.sleep()");
    }

    public String toString() {
        return name;
    }
}

public class Rodent9 {
    private static RandomRodentGenerator gen = new RandomRodentGenerator();

    public static void main(String[] args) {
        Rodent[] rodents = new Rodent[10];
        for (Rodent r : rodents) {
            r = gen.next();
            System.out.println(r + ": ");
            r.eat();
            r.run();
            r.sleep();
        }
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 8

Exercise 8: Modify Music3.java so that it randomly creates Instrument objects the way Shapes.java does.

package polymorphism.music8;

import java.util.*;

public class RandomInstrumentGenerator {
    private Random rand = new Random();

    public Instrument next() {
        switch (rand.nextInt(7)) {
        default:
        case 0:
            return new Wind();
        case 1:
            return new Percussion();
        case 2:
            return new Stringed();
        case 3:
            return new Keyboard();
        case 4:
            return new Brass();
        case 5:
            return new Woodwind();
        case 6:
            return new Piano();
        }
    }
}
package polymorphism.music;

public enum Note {
    MIDDLE_C, C_SHARP, B_FLAT; // Etc.
}
package polymorphism.music8;

import polymorphism.music.Note;

class Instrument {
    void play(Note n) {
        System.out.println("Instrument.play() " + n);
    }

    public String toString() {
        return "Instrument";
    }

    void adjust() {
        System.out.println("Adjusting Instrument");
    }
}

class Wind extends Instrument {
    void play(Note n) {
        System.out.println("Wind.play() " + n);
    }

    public String toString() {
        return "Wind";
    }

    void adjust() {
        System.out.println("Adjusting Wind");
    }
}

class Percussion extends Instrument {
    void play(Note n) {
        System.out.println("Percussion.play() " + n);
    }

    public String toString() {
        return "Percussion";
    }

    void adjust() {
        System.out.println("Adjusting Percussion");
    }
}

class Stringed extends Instrument {
    void play(Note n) {
        System.out.println("Stringed.play() " + n);
    }

    public String toString() {
        return "Stringed";
    }

    void adjust() {
        System.out.println("Adjusting Stringed");
    }
}

class Keyboard extends Instrument {
    void play(Note n) {
        System.out.println("Keyboard.play() " + n);
    }

    public String toString() {
        return "Keyboard";
    }

    void adjust() {
        System.out.println("Adjusting Keyboard");
    }
}

class Brass extends Wind {
    void play(Note n) {
        System.out.println("Brass.play() " + n);
    }

    public String toString() {
        return "Brass";
    }

    void adjust() {
        System.out.println("Adjusting Brass");
    }
}

class Woodwind extends Wind {
    void play(Note n) {
        System.out.println("Woodwind.play() " + n);
    }

    public String toString() {
        return "Woodwind";
    }
}

class Piano extends Keyboard {
    void play(Note n) {
        System.out.println("Piano.play() " + n);
    }

    public String toString() {
        return "Piano";
    }
}

public class Music8 {
    // Doesn't care about type, so new types
    // added to the system still work right:
    public static void tune(Instrument i) {
        // ...
        i.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] e) {
        for (Instrument i : e)
            tune(i);
    }

    private static RandomInstrumentGenerator gen = new RandomInstrumentGenerator();

    public static void main(String[] args) {
        // Upcasting during addition to the array:
        Instrument[] orchestra = new Instrument[20];
        // fill up orchestra array wth instruments:
        for (int i = 0; i < orchestra.length; i++)
            orchestra[i] = gen.next();
        tuneAll(orchestra);
        for (Instrument i : orchestra)
            System.out.println(i);
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 7

Exercise 7: Add a new type of Instrument to Music3.java and verify that polymorphism works for your new type.

package polymorphism.music;

public enum Note {
    MIDDLE_C, C_SHARP, B_FLAT; // Etc.
}
package polymorphism.music7;

import polymorphism.music.Note;

class Instrument {
    void play(Note n) {
        System.out.println("Instrument.play() " + n);
    }

    public String toString() {
        return "Instrument";
    }

    void adjust() {
        System.out.println("Adjusting Instrument");
    }
}

class Wind extends Instrument {
    void play(Note n) {
        System.out.println("Wind.play() " + n);
    }

    public String toString() {
        return "Wind";
    }

    void adjust() {
        System.out.println("Adjusting Wind");
    }
}

class Percussion extends Instrument {
    void play(Note n) {
        System.out.println("Percussion.play() " + n);
    }

    public String toString() {
        return "Percussion";
    }

    void adjust() {
        System.out.println("Adjusting Percussion");
    }
}

class Stringed extends Instrument {
    void play(Note n) {
        System.out.println("Stringed.play() " + n);
    }

    public String toString() {
        return "Stringed";
    }

    void adjust() {
        System.out.println("Adjusting Stringed");
    }
}

class Keyboard extends Instrument {
    void play(Note n) {
        System.out.println("Keyboard.play() " + n);
    }

    public String toString() {
        return "Keyboard";
    }

    void adjust() {
        System.out.println("Adjusting Keyboard");
    }
}

class Brass extends Wind {
    void play(Note n) {
        System.out.println("Brass.play() " + n);
    }

    public String toString() {
        return "Brass";
    }

    void adjust() {
        System.out.println("Adjusting Brass");
    }
}

class Woodwind extends Wind {
    void play(Note n) {
        System.out.println("Woodwind.play() " + n);
    }

    public String toString() {
        return "Woodwind";
    }
}

class Piano extends Keyboard {
    void play(Note n) {
        System.out.println("Piano.play() " + n);
    }

    public String toString() {
        return "Piano";
    }
}

public class Music7 {
    // Doesn't care about type, so new types
    // added to the system still work right:
    public static void tune(Instrument i) {
        // ...
        i.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] e) {
        for (Instrument i : e)
            tune(i);
    }

    public static void main(String[] args) {
        // Upcasting during addition to the array:
        Instrument[] orchestra = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind(),
                new Piano() };
        tuneAll(orchestra);
        for (Instrument i : orchestra)
            System.out.println(i);
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 6

Exercise 6: Change Music3.java so that what( ) becomes the root Object method toString( ). Try printing the Instrument objects using System.out.println( ) (without any casting).

package polymorphism.music;

public enum Note {
    MIDDLE_C, C_SHARP, B_FLAT; // Etc.
}
import polymorphism.music.Note;

class Instrument {
    void play(Note n) {
        System.out.println("Instrument.play() " + n);
    }

    public String toString() {
        return "Instrument";
    }

    void adjust() {
        System.out.println("Adjusting Instrument");
    }
}

class Wind extends Instrument {
    void play(Note n) {
        System.out.println("Wind.play() " + n);
    }

    public String toString() {
        return "Wind";
    }

    void adjust() {
        System.out.println("Adjusting Wind");
    }
}

class Percussion extends Instrument {
    void play(Note n) {
        System.out.println("Percussion.play() " + n);
    }

    public String toString() {
        return "Percussion";
    }

    void adjust() {
        System.out.println("Adjusting Percussion");
    }
}

class Stringed extends Instrument {
    void play(Note n) {
        System.out.println("Stringed.play() " + n);
    }

    public String toString() {
        return "Stringed";
    }

    void adjust() {
        System.out.println("Adjusting Stringed");
    }
}

class Brass extends Wind {
    void play(Note n) {
        System.out.println("Brass.play() " + n);
    }

    public String toString() {
        return "Brass";
    }

    void adjust() {
        System.out.println("Adjusting Brass");
    }
}

class Woodwind extends Wind {
    void play(Note n) {
        System.out.println("Woodwind.play() " + n);
    }

    public String toString() {
        return "Woodwind";
    }
}

public class Music6 {
    // Doesn't care about type, so new types
    // added to the system still work right:
    public static void tune(Instrument i) {
        // ...
        i.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] e) {
        for (Instrument i : e)
            tune(i);
    }

    public static void main(String[] args) {
        // Upcasting during addition to the array:
        Instrument[] orchestra = { new Wind(), new Percussion(), new Stringed(), new Brass(), new Woodwind() };
        tuneAll(orchestra);
        for (Instrument i : orchestra)
            System.out.println(i);
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 5

Exercise 5: Starting from Exercise 1, add a wheels( ) method in Cycle, which returns the number of wheels. Modify ride( ) to call wheels( ) and verify that polymorphism works.

package polymorphism.biking;

class Cycle {
    private String name = "Cycle";
    private int wheels = 0;

    public static void travel(Cycle c) {
        System.out.println("Cycle.ride() " + c);
    }

    public int wheels() {
        return wheels;
    }

    public String toString() {
        return this.name;
    }
}

class Unicycle extends Cycle {
    private String name = "Unicycle";
    private int wheels = 1;

    @Override
    public int wheels() {
        return wheels;
    }

    public String toString() {
        return this.name;
    }
}

class Bicycle extends Cycle {
    private String name = "Bicycle";
    private int wheels = 2;

    @Override
    public int wheels() {
        return wheels;
    }

    public String toString() {
        return this.name;
    }

}

class Tricycle extends Cycle {
    private String name = "Tricycle";
    private int wheels = 3;

    @Override
    public int wheels() {
        return wheels;
    }

    public String toString() {
        return this.name;
    }
}

public class Biking5 {
    public static void ride(Cycle c) {
        c.travel(c);
        System.out.println("wheels: " + c.wheels());
    }

    public static void main(String[] args) {
        Unicycle u = new Unicycle();
        Bicycle b = new Bicycle();
        Tricycle t = new Tricycle();
        ride(u); // upcast to Cycle
        ride(b);
        ride(t);
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 4

Exercise 4: Add a new type of Shape to Shapes.java and verify in main( ) that polymorphism works for your new type as it does in the old types.

package polymorphism.shape;

public class Shape {
    public void draw() {
    }

    public void erase() {
    }

    public void amend() {
        System.out.println("Shape.amend()");
    }
}
package polymorphism.shape;

public class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("Triangle.draw()");
    }

    @Override
    public void erase() {
        System.out.println("Triangle.erase()");
    }

    @Override
    public void amend() {
        System.out.println("Triangle.amend()");
    }
}
package polymorphism.shape;

public class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.println("Rectangle.draw()");
    }

    @Override
    public void erase() {
        System.out.println("Rectangle.erase()");
    }

    @Override
    public void amend() {
        System.out.println("Rectangle.amend()");
    }
}
package polymorphism.shape;

public class Square extends Shape {
    @Override
    public void draw() {
        System.out.println("Square.draw()");
    }

    @Override
    public void erase() {
        System.out.println("Square.erase()");
    }

    @Override
    public void amend() {
        System.out.println("Square.amend()");
    }
}
package polymorphism.shape;

public class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Circle.draw()");
    }

    @Override
    public void erase() {
        System.out.println("Circle.erase()");
    }

    @Override
    public void amend() {
        System.out.println("Circle.amend()");
    }
}
package polymorphism.shape;

import java.util.*;

public class RandomShapeGenerator4 {
    private Random rand = new Random();

    public Shape next() {
        switch (rand.nextInt(4)) {
        default:
        case 0:
            return new Circle();
        case 1:
            return new Square();
        case 2:
            return new Triangle();
        case 3:
            return new Rectangle();
        }
    }
}
import polymorphism.shape.*;                                                                                        
                                                                                                                   
public class Shapes4 {                                                                                              
    private static RandomShapeGenerator4 gen = new RandomShapeGenerator4();                                        
                                                                                                                   
    public static void main(String[] args) {                                                                        
        Shape[] s = new Shape[10];                                                                                  
        // fill up the array wth shapes:                                                                            
        for (int i = 0; i < s.length; i++)                                                                          
            s[i] = gen.next();                                                                                      
        // make polymorphic method calls:                                                                          
        for (Shape shp : s) {                                                                                      
            shp.draw();                                                                                            
            shp.amend();                                                                                            
        }                                                                                                          
    }                                                                                                              
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 3

Exercise 3: Add a new method in the base class of Shapes.java that prints a message, but don’t override it in the derived classes. Explain what happens. Now override it in one of the derived classes but not the others, and see what happens. Finally, override it in all the derived classes.

package polymorphism.shape;
import java.util.*;
public class RandomShapeGenerator
{
    private Random rand = new Random();
    public Shape next()
    {
        switch(rand.nextInt(3))
        {
            default:
            case 0: return new Circle();
            case 1: return new Square();
            case 2: return new Triangle();
        }
    }
}
package polymorphism.shape;
public class Shape
{
    public void draw()
    {
    }
    public void erase()
    {
    }
    public void amend()
    {
        System.out.println("Shape.amend()");
    }
}
package polymorphism.shape;
public class Circle extends Shape
{
    @Override public void draw()
    {
        System.out.println("Circle.draw()");
    }
    @Override public void erase()
    {
        System.out.println("Circle.erase()");
    }
    @Override public void amend()
    {
        System.out.println("Circle.amend()");
    }
}
package polymorphism.shape;
public class Square extends Shape
{
    @Override public void draw()
    {
        System.out.println("Square.draw()");
    }
    @Override public void erase()
    {
        System.out.println("Square.erase()");
    }
    @Override public void amend()
    {
        System.out.println("Square.amend()");
    }
}
package polymorphism.shape;
public class Triangle extends Shape
{
    @Override public void draw()
    {
        System.out.println("Triangle.draw()");
    }
    @Override public void erase()
    {
        System.out.println("Triangle.erase()");
    }
    @Override public void amend()
    {
        System.out.println("Triangle.amend()");
    }
}
import polymorphism.shape.*;

public class Shapes3
{
    private static RandomShapeGenerator gen = new RandomShapeGenerator();
    public static void main(String[] args)
    {
        Shape[] s = new Shape[10];
        // fill up the array wth shapes:
        for(int i = 0; i < s.length; i++)
            s[i] = gen.next();
        // make polymorphic method calls:
        for(Shape shp : s)
        {
            shp.draw();
            shp.amend();
        }  
    }
}

Output:

Thinking in Java Fourth Edition Bruce Eckel Chapter 7 Exercise 2

Exercise 2: Add the @Override annotation to the shapes example.

package polymorphism.shape;
public class Shape
{
    public void draw()
    {
    }
    public void erase()
    {
    }
}
package polymorphism.shape;
public class Square extends Shape
{
    @Override public void draw()
    {
        System.out.println("Square.draw()");
    }
    @Override public void erase()
    {
        System.out.println("Square.erase()");
    }
}
package polymorphism.shape;
public class Triangle extends Shape
{
    @Override public void draw()
    {
        System.out.println("Triangle.draw()");
    }
    @Override public void erase()
    {
        System.out.println("Triangle.erase()");
    }
}
package polymorphism.shape;
public class Circle extends Shape
{
    @Override public void draw()
    {
        System.out.println("Circle.draw()");
    }
    @Override public void erase()
    {
        System.out.println("Circle.erase()");
    }
}
package polymorphism.shape;
import java.util.*;
public class RandomShapeGenerator
{
    private Random rand = new Random();
    public Shape next()
    {
        switch(rand.nextInt(3))
        {
            default:
            case 0: return new Circle();
            case 1: return new Square();
            case 2: return new Triangle();
        }
    }
}
import polymorphism.shape.*;

public class Shapes
{
    private static RandomShapeGenerator gen = new RandomShapeGenerator();
    public static void main(String[] args)
    {
        Shape[] s = new Shape[10];
        // fill up the array wth shapes:
        for(int i = 0; i < s.length; i++)
            s[i] = gen.next();
        // make polymorphic method calls:
        for(Shape shp : s)
            shp.draw();
    }
}

Output: