[reading notes] polymorphism in Chapter 8 of Java programming thought

  1. Polymorphism is the third basic feature after data abstraction and inheritance. Polymorphism separates the interface from the implementation by separating what to do and how to do it. Polymorphism can not only improve the organization and readability of code, but also create extensible programs. "Encapsulation" creates new data types by merging features and behaviors; "Implementation hiding" separates the interface from the implementation by "privatizing" the details; The function of polymorphism is to eliminate the coupling relationship between types. Polymorphic methods allow one type to distinguish from other similar types as long as they are derived from the same base class.
  2. Associating a method call with a method body is called binding. Binding before program execution (if any, implemented by compiler and linker) is called pre binding. Late binding: it means binding according to the type of object at runtime. Late binding is also called dynamic binding or runtime binding. The late binding mechanism varies from programming language to programming language, but in any case, some "type information" must be placed in the object. In Java, all methods are late bound except static method and final method (private method belongs to final method).
  3. Once we know the fact that all methods in Java are polymorphic through dynamic binding, we can write program code that only deals with base classes. Or to put it another way, send a message to an object and let the object decide what to do. At compile time, the compiler does not need any special information to make the correct call.
  4. In a well-designed OPP program, most or all methods will communicate with the base class interface. Such programs are extensible because they can inherit new data types from common base classes and add some new functions. Those methods that operate on the base class interface can be applied to the new class without any changes. Polymorphism is an important technology that allows programmers to "separate changed things from unchanged things".
  5. Polymorphic defect: "covering private methods"; "Direct access to a domain"; "Access static methods"; Only ordinary method calls can be polymorphic. Any domain access operation will be resolved by the compiler, so it is not polymorphic. If a method is static, its behavior is not polymorphic. Static methods are associated with classes, not with an object.
package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 5:54 PM
 */
public class PrivateOverride {
    private void f(){
        System.out.println("private f()");
    }

    public static void main(String[] args) {
        PrivateOverride privateOverride = new Derived();
        privateOverride.f();
    }
}

class Derived extends PrivateOverride{
    public void f(){
        System.out.println("public f()");
    }
}
package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 5:57 PM
 */
public class FieldAccess {
    public static void main(String[] args) {
        /**
         * Upcast
         */
        Super sup = new Sub();
        System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField());

        Sub sub = new Sub();
        System.out.println("sup.field = " + sub.field + ", sup.getField() = " + sub.getField() + ", sum.getSuperField() = " + sub.getSuperField());

    }
}

class Super {
    public int field = 0;

    public int getField() {
        return field;
    }
}

class Sub extends Super {
    public int field = 1;

    @Override
    public int getField() {
        return field;
    }

    public int getSuperField() {
        return super.field;
    }
}
package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 6:07 PM
 */
public class StaticPolymorphism {
    public static void main(String[] args) {
        /**
         * Upcast
         */
        StaticSuper sup = new StaticSub();
        System.out.println(sup.staticGet());
        System.out.println(sup.dynamicGet());
    }
}

class StaticSuper{
    public static String staticGet() {
        return "Base staticGet()";
    }

    public String dynamicGet() {
        return "Base dynamicGet()";
    }
}

class StaticSub extends StaticSuper{
    public static String staticGet() {
        return "Derived staticGet()";
    }

    @Override
    public String dynamicGet() {
        return "Derived dynamicGet()";
    }
}
  1. The constructor is not polymorphic (the constructor is actually a static method, but the static declaration is implicit). The constructor of the base class is always called during the construction of the exported class, and is gradually linked upward according to the inheritance level, so that the constructor of each base class can be called. Call the constructor in the following order:
    1) Call the constructor of the base class.
    2) The initialization methods of members are called in the declared order.
    3) Call the body of the exported class constructor.
package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 6:18 PM
 */
public class Sandwich extends PortableLunch {
    private Bread bread = new Bread();
    private Cheese cheese = new Cheese();
    private Lettuce lettuce = new Lettuce();

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

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

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 Lunch extends Meal{
    Lunch() {
        System.out.println("Lunch()");
    }
}

class PortableLunch extends Lunch{
    PortableLunch() {
        System.out.println("PortableLunch()");
    }
}
  1. The call of dynamic binding is determined at run time, because the object cannot know whether it belongs to the subclass of the method or the exported class of that class. If you want to call a dynamically bound method inside the constructor, you need to use the definition after the method is overridden. However, the effect of this call can be quite unpredictable, because the overridden method will be called before the object is fully constructed. This may cause some unpredictable errors. The constructor's job is actually to create objects (which is not an ordinary job). If the constructor is only a step in the process of object construction, and the class to which the object belongs is exported from the class to which the constructor belongs, the export part is still uninitialized when the current constructor is being called.
package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 7:14 PM
 */
public class PolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
}

class Glyph {
    void draw() {
        System.out.println("Sup-Glyph.draw()");
    }

    Glyph() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph() after draw()");
    }
}

class RoundGlyph extends Glyph {
    private int radius = 1;

    RoundGlyph(int radius) {
        this.radius = radius;
        System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
    }

    @Override
    void draw() {
        System.out.println("Sub-RoundGlyph.draw(), radius = " + radius);
    }
}

Actual process of initialization:
1) Initialize the storage space allocated to the object to binary 0 before anything else happens;
2) Call the base class constructor as described earlier. At this point, the draw() method is called (before calling the RoundGlyph constructor). Because of step 1, radius is 0 at this time.
3) Call the initialization methods of members in the declared order;
4) Call the constructor body of the exported class.

  1. An effective rule for writing constructors: "use as simple a method as possible to make the object enter the normal state; if possible, avoid calling other methods." the only methods that can be safely called in the constructor are the final method in the base class (also applicable to private methods). These methods cannot be covered, so there will be no such "outrageous" problem.
  2. Java SE5 adds a covariant return type, which represents an export type that can return the return type of the base class method in the overridden method of the export class.
package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 7:29 PM
 */
public class CovariantReturn {
    public static void main(String[] args) {
        Mill mill  = new Mill();
        Grain grain = new Grain();
        System.out.println(grain);
        mill = new WheatMill();
        grain = mill.process();
        System.out.println(grain);
    }
}

class Grain{
    @Override
    public String toString() {
        return "Grain";
    }
}

class Wheat extends Grain{
    @Override
    public String toString() {
        return "Wheat";
    }
}

class Mill{
    Grain process() {
        return new Grain();
    }
}

class WheatMill extends Mill{
    @Override
    Wheat process() {
        return new Wheat();
    }
}
  1. In fact, when we use ready-made classes to build new classes, if we first consider using inheritance technology, it will increase our design burden and make things unnecessarily complicated. A general rule is: "use inheritance to express differences between behaviors, and use fields to express changes in state".
  2. Downward transformation and runtime type identification (RTTI), the content of RTTI includes not only transformation processing. For example, it also provides a way for you to see the types you want to deal with before trying to transition down.
package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 7:43 PM
 */
public class RTTI {
    public static void main(String[] args) {
        Useful[] usefuls = {
                new Useful(),
                new MoreUseful()
        };

        usefuls[0].f();
        usefuls[1].g();
        /**
         * Downcast/RTTI
         */
        ((MoreUseful)usefuls[1]).u();
        /**
         * Exception thrown
         */
        ((MoreUseful)usefuls[0]).u();
    }
}

class Useful {
    public void f() {
    }

    public void g() {
    }
}

class MoreUseful extends Useful {
    @Override
    public void f() {
    }

    @Override
    public void g() {
    }

    public void u() {
    }

    public void v() {
    }

    public void w() {
    }
}
  1. Without data abstraction and inheritance, it is impossible to understand or even create polymorphic examples. In order to effectively use polymorphism and even object-oriented technology, we must expand our programming vision to include not only the members and messages of individual classes, but also the common characteristics and relationships between classes.

Exercise 1: create a Circle class with Subclasses Unicycle, Bicycle, and Tricycle. Demonstrate that instances of each type can be transformed upward to Cycle via the ride() method.

package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 7:59 PM
 */
public class Biking {
    public static void ride(Cycle cycle) {
        cycle.travel("" + cycle);
    }

    public static void main(String[] args) {
        Unicycle unicycle = new Unicycle();
        Bicycle bicycle  = new Bicycle();
        Tricycle tricycle = new Tricycle();
        ride(unicycle);
        ride(bicycle);
        ride(tricycle);
    }
}

class Cycle {
    public void travel(String s) {
        System.out.println("Cycle.travel " + s);
    }
}

class Unicycle extends Cycle {
    @Override
    public String toString() {
        return "Unicycle";
    }
}

class Bicycle extends Cycle {
    @Override
    public String toString() {
        return "Bicycle";
    }
}

class Tricycle extends Cycle {
    @Override
    public String toString() {
        return "Tricycle";
    }
}

Exercise 2: add the @ Override annotation to the geometry example.

package thinkinginjava.charpenter8;

import java.util.Random;

/**
 * @author Spring-_-Bear
 * @version 2021/09/28 7:44 PM
 */
public class Shapes {
    private static RandomShapeGenerator generator = new RandomShapeGenerator();

    public static void main(String[] args) {
        Shape[] shapes = new Shape[9];
        /**
         * Fill up the array with Shape references
         */
        for (int i = 0; i < shapes.length; i++) {
            shapes[i] = generator.next();
        }

        for (Shape shp : shapes) {
            shp.draw();
        }
    }
}

class Shape {
    public void draw() {
    }

    public void erase() {
    }
}

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

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

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

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

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

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

class RandomShapeGenerator {
    private Random random = new Random(55);

    public Shape next() {
        switch (random.nextInt(3)) {
            case 0:
                return new Circle();
            case 1:
                return new Square();
            case 2:
                return new Triangle();
            default:
        }
        
        return null;
    }
}

Exercise 3: add a new method in the base class Shape.java to print a message, but do not overwrite this method in the exported class. Please explain what happened. Now, override the method in one of the exported classes, and don't override it in the other exported classes. Observe what happens. Finally, override this method in all exported classes.

package thinkinginjava.charpenter8;

import java.util.Random;

/**
 * @author Spring-_-Bear
 * @version 2021/09/28 7:44 PM
 */
public class Shapes {
    private static RandomShapeGenerator generator = new RandomShapeGenerator();

    public static void main(String[] args) {
        Shape[] shapes = new Shape[9];
        /**
         * Fill up the array with Shape references
         */
        for (int i = 0; i < shapes.length; i++) {
            shapes[i] = generator.next();
        }

        for (Shape shp : shapes) {
            shp.draw();
            shp.erase();
            shp.amend();
        }
    }
}

class Shape {
    public void draw() {
        System.out.println("Shape.draw()");
    }

    public void erase() {
        System.out.println("Shape.amend()");
    }

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

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()");
    }
}

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()");
    }
}

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()");
    }
}

class RandomShapeGenerator {
    private Random random = new Random(55);

    public Shape next() {
        switch (random.nextInt(3)) {
            case 0:
                return new Circle();
            case 1:
                return new Square();
            case 2:
                return new Triangle();
            default:
        }

        return null;
    }
}

Exercise 4: add a new Shape type to Shapes.java and verify in the main() method that polymorphism works on the new type as it does in the old type.

package thinkinginjava.charpenter8;

import java.util.Random;

/**
 * @author Spring-_-Bear
 * @version 2021/09/28 7:44 PM
 */
public class Shapes {
    private static RandomShapeGenerator generator = new RandomShapeGenerator();

    public static void main(String[] args) {
        Shape[] shapes = new Shape[9];
        /**
         * Fill up the array with Shape references
         */
        for (int i = 0; i < shapes.length; i++) {
            shapes[i] = generator.next();
        }

        for (Shape shp : shapes) {
            shp.draw();
            shp.erase();
            shp.amend();
        }
    }
}

class Shape {
    public void draw() {
        System.out.println("Shape.draw()");
    }

    public void erase() {
        System.out.println("Shape.amend()");
    }

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

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()");
    }
}

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()");
    }
}

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()");
    }
}

class RandomShapeGenerator {
    private Random random = new Random(55);

    public Shape next() {
        switch (random.nextInt(4)) {
            case 0:
                return new Circle();
            case 1:
                return new Square();
            case 2:
                return new Triangle();
            case 3:
                return new Oval();
            default:
        }

        return null;
    }
}

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

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

    @Override
    public void amend() {
        System.out.println("Oval.amend()");
    }
}

Exercise 5: Based on exercise 1, add the wheels() method to the Cycle, which will return the number of wheels. Modify the ride() method to call the wheels() method and verify that polymorphism works.

package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 7:59 PM
 */
public class Biking {
    public static void ride(Cycle cycle) {
        cycle.travel("" + cycle);
        cycle.wheels();
    }

    public static void main(String[] args) {
        Unicycle unicycle = new Unicycle();
        Bicycle bicycle = new Bicycle();
        Tricycle tricycle = new Tricycle();
        ride(unicycle);
        ride(bicycle);
        ride(tricycle);
    }
}

class Cycle {
    private int wheels = 4;

    public void travel(String s) {
        System.out.println("Cycle.travel " + s);
    }

    public void wheels() {
        System.out.println("Cycle.wheels = " + wheels);
    }
}

class Unicycle extends Cycle {
    private int wheels = 1;
    @Override
    public String toString() {
        return "Unicycle";
    }

    @Override
    public void wheels() {
        System.out.println("Unicycle.wheels = " + wheels);
    }
}

class Bicycle extends Cycle {
    private int wheels = 2;

    @Override
    public String toString() {
        return "Bicycle";
    }

    @Override
    public void wheels() {
        System.out.println("Bicycle.wheels = " + wheels);
    }
}

class Tricycle extends Cycle {
    private int wheels = 3;

    @Override
    public String toString() {
        return "Tricycle";
    }

    @Override
    public void wheels() {
        System.out.println("Tricycle.wheels = " + wheels);
    }
}

Exercise 6: modify Music3.java so that the what() method becomes the toString() method of the root Object. Use the System.out.println() method to print the Instrument Object (without upward transformation).

package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 2021/09/28 8:04 PM
 */
public class Music3 {
    public static void tune(Instrument instrument) {
        instrument.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] instruments) {
        for (Instrument instrument : instruments) {
            tune(instrument);
        }
    }

    public static void main(String[] args) {
        /**
         * Upcasting during addition to the array.
         */
        Instrument[] instruments = {
          new Wind(),
          new Percussion(),
          new Stringed(),
          new Brass(),
          new Woodwind()
        };

        tuneAll(instruments);
    }
}

enum Note {
    MIDDLE_C, C_SHARP, B_FLAT;
}

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

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

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

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

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

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

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

    @Override
    public String toString() {
        return super.toString();
    }

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

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

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

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

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

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

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

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

Exercise 7: add a new type Instrument to Music.java and verify that polymorphism works on the added new type.

package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 2021/09/28 8:04 PM
 */
public class Music3 {
    public static void tune(Instrument instrument) {
        instrument.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] instruments) {
        for (Instrument instrument : instruments) {
            tune(instrument);
        }
    }

    public static void main(String[] args) {
        /**
         * Upcasting during addition to the array.
         */
        Instrument[] instruments = {
                new Wind(),
                new Percussion(),
                new Stringed(),
                new Brass(),
                new Woodwind(),
                new Piano()
        };

        tuneAll(instruments);
    }
}

enum Note {
    MIDDLE_C, C_SHARP, B_FLAT;
}

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

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

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

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

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

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

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

    @Override
    public String toString() {
        return super.toString();
    }

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

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

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

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

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

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

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

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

class Piano extends Instrument {
    @Override
    void play(Note note) {
        System.out.println("Piano.play() " + note);
    }
}

Exercise 8: modify Music3.java so that it can randomly create the object of the Instrument as in Shapes.java.

package thinkinginjava.charpenter8;

import java.util.Random;

/**
 * @author Spring-_-Bear
 * @version 2021/09/28 8:04 PM
 */
public class Music3 {
    public static void tune(Instrument instrument) {
        instrument.play(Note.MIDDLE_C);
    }

    public static void tuneAll(Instrument[] instruments) {
        for (Instrument instrument : instruments) {
            tune(instrument);
        }
    }

    public static void main(String[] args) {
        Instrument[] instruments = new Instrument[6];
        RandomInstrumentGenerator randomInstrumentGenerator = new RandomInstrumentGenerator();

        for (int i = 0; i < instruments.length; i++) {
            instruments[i] = randomInstrumentGenerator.next();
        }

        tuneAll(instruments);
    }
}

enum Note {
    MIDDLE_C, C_SHARP, B_FLAT;
}

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

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

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

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

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

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

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

    @Override
    public String toString() {
        return super.toString();
    }

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

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

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

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

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

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

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

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

class Piano extends Instrument {
    @Override
    void play(Note note) {
        System.out.println("Piano.play() " + note);
    }
}

class RandomInstrumentGenerator {
    private Random random = new Random(47);

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

        return null;
    }
}

Exercise 9: create an inheritance hierarchy of rod (Rodent): Mouse, Gerbil, Hamster, etc. In the base class, methods common to all rodents are provided. In the exported class, these methods are overridden according to the specific Rodent type so that they can perform different behaviors. Create a Robent array, fill in different Rode nt types, and then call the base class method to observe what happens.

package thinkinginjava.charpenter8;

import java.util.Random;

/**
 * @author Spring-_-Bear
 * @version 2021/9/30 23:07
 */
public class RodentTester {
    private static RandomRodentGenerator generator = new RandomRodentGenerator();

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

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

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

    @Override
    public String toString() {
        return "Rodent";
    }
}

class Mouse extends Rodent {
    @Override
    protected void eat() {
        System.out.println("Mouse.eat()");
    }

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

    @Override
    public String toString() {
        return "Mouse";
    }
}

class Gerbil extends Rodent {
    @Override
    protected void run() {
        System.out.println("Gerbil.run()");
    }

    @Override
    protected void eat() {
        System.out.println("Gerbil.eat()");
    }

    @Override
    public String toString() {
        return "Gerbil";
    }
}

class RandomRodentGenerator {
    private Random random = new Random(55);

    public Rodent next() {
        switch (random.nextInt(2)) {
            case 0:
                return new Mouse();
            case 1:
                return new Gerbil();
            default:
        }

        return null;
    }
}

Exercise 10: create a base class with two methods. The second method can be called in the first method. It then generates an derived class that inherits from the base class and overrides the second method in the infrastructure class. Create an object for the exported class, transform it up to the base type, and call the first method to explain what happened.

package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 2021/10/1 14:55
 */
public class PolyMethod extends SuperMethod {
    @Override
    protected void method2() {
        System.out.println("PolyMethod.method()");
    }

    public static void main(String[] args) {
        /**
         * Upcasting
         */
        SuperMethod polyMethod = new PolyMethod();
        polyMethod.method1();
    }
}

class SuperMethod{
    protected void method1(){
        System.out.println("SuperMethod.method1()");
        method2();
    }

    protected void method2() {
        System.out.println("SuperMethod.method2()");
    }
}

Exercise 11: add the Pickle class to Sandwich.java.

package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 9/29/21 6:18 PM
 */
public class Sandwich extends PortableLunch {
    private Bread bread = new Bread();
    private Cheese cheese = new Cheese();
    private Lettuce lettuce = new Lettuce();
    private Pickle pickle = new Pickle();

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

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

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 Lunch extends Meal{
    Lunch() {
        System.out.println("Lunch()");
    }
}

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

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

Exercise 12: modify exercise 9 to demonstrate the initialization order of the base and exported classes. Then add member objects to the base and export classes and explain the order in which initialization occurs during the architecture.

package thinkinginjava.charpenter8;

/**
 * @author Spring-_-Bear
 * @version 2021/9/30 23:07
 */
public class RodentTester {
    public static void main(String[] args) {
        Rodent mouse = new Mouse();
        System.out.println(mouse + ": ");
        mouse.eat();
        mouse.run();
        mouse.sleep();
    }
}

class Characteristic {
    private String s;

    Characteristic(String s) {
        this.s = s;
        System.out.println("Creating Characteristic " + s);
    }
}

class Description {
    private String s;

    Description(String s) {
        this.s = s;
        System.out.println("Creating Description " + s);
    }
}

class Rodent {
    private String name = "Rodent";
    private Characteristic c = new Characteristic("has tail");
    private Description d = new Description("small mammal");

    Rodent() {
        System.out.println("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()");
    }

    @Override
    public String toString() {
        return name;
    }
}

class Mouse extends Rodent {
    private String name = "Mouse";
    private Characteristic c = new Characteristic("likes cheese");
    private Description d = new Description("nocturnal");
    Mouse() {
        System.out.println("Mouse()");
    }
    @Override
    protected void eat() {
        System.out.println("Mouse.eat()");
    }
    @Override
    protected void run() {
        System.out.println("Mouse.run()");
    }
    @Override
    protected void sleep() {
        System.out.println("Mouse.sleep()");
    }
    @Override
    public String toString() { return name; }
}

Exercise 13: add a finalize() method in ReferenceCounting.java to verify the termination condition in (see Chapter 5).

Exercise 14: modify exercise 12 so that one of its member objects becomes a shared object with a reference count and verify that it works correctly.

Exercise 15: add a rectangle glyph to PolyConstructors.java and verify that the problems described in this section occur.

Exercise 16: follow the example of Transmogrify.java to create a Starship class that contains an AlertStatus reference that can indicate three different states. Include ways to change these states.

Exercise 17: using the hierarchy of cycles in exercise 1, add the balance() method to Unicycle and Bicycle instead of Tricycle. Create instances of all three types and transform them up into a Cycle array. Try calling balance() on each element of the array and observe the result. Then transition them down, call balance() again, and see what happens.

Posted by mimilaw123 on Fri, 01 Oct 2021 13:48:00 -0700