"Java Programming Ideas - Chapter 8 (Polymorphism)"

polymorphism

Polymorphism is the third fundamental feature after data abstraction and inheritance.

8.1 Upward Transformation Again

/**
 * 基类
 */
public class Instrument {

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

}
/**
 * 导出类
 */
public class Wind extends Instrument{
    public void play(Note n) {
        System.out.println("Wind play()"+n);
    }
}
public class Music {
    public static void tune(Instrument i) {
        i.play(Note.MIDDLE_C);
    }
    public static void main(String[] args) {
        //向上转型
        Wind flute =  new Wind();
        tune(flute);
    }
}

Upcasting masks the type of the object and avoids overloading the tune method for each object.

Polymorphism allows methods to be defined that only accept base classes as parameters, and can also be used normally for exported classes.

8.2 Transfer

How does the compiler know which method the tune method points to? Actually the compiler has no way of knowing.
Associating a method call with a method subject is called binding .
1. Method call binding
Early binding: Binding before program execution.
Late Binding: Binding at runtime based on the type of the object.

In Java, except static methods and final methods, all other methods are late bound. Polymorphism is achieved through dynamic binding.
Only non-private methods can be overridden; only ordinary method calls can be polymorphic, and static methods are associated with classes, not individual objects.

8.3 Constructors and Polymorphism

  1. Constructor calling order
    write picture description here
    In the derived class, the public and protected members of the base class can be accessed, which means that all members of the base class must be guaranteed to be valid in the derived class. Therefore, the base class constructor must be called first to ensure that the members of the base class are effectively initialized.
  2. Behavior of polymorphic methods inside constructors

The question arises from the hierarchy of constructor calls: what happens if a dynamically bound method of an object being constructed is called inside a constructor?

If you want to call a dynamically bound method inside the constructor, the subclass needs to override this method.

/**
 * 构造器内部动态调用
 */
public class PolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
}
class Glyph{
    void draw(){
        System.out.println("Glyph.draw()");
    }
    public Glyph() {
        System.out.println("Glyph before draw()");
        draw();
        System.out.println("Glyph after draw()");
    }
}
class RoundGlyph extends Glyph{
    private int radius = 1;

    public RoundGlyph(int r) {
        radius = r;
        System.out.println("RoundGlyph.RoundGlyph(),radius = "+radius);
    }
    void draw(){
        System.out.println("RoundGlyph.draw,radius = "+radius);
    }
}

Output result:

Glyph before draw()
RoundGlyph.draw,radius = 0 //Dynamic call is implemented, but the initial value of radius is not 1
Glyph after draw()
RoundGlyph.RoundGlyph(),radius = 5

The actual process of initialization of the constructor:
1) Before anything else happens, the storage space allocated to the object is initialized to binary zero.
2) Call the base class constructor (call the overridden draw method), the value of radius is zero due to 1
) 3) Call the initialization methods of members in the order of declaration
4) Call the constructor body of the exported class.

Therefore, the only method that can be safely called in the constructor is the final modified method, and calling dynamic methods should be avoided.

8.4 Covariant return types

Covariant return type: An overridden method in the derived class can return some derived type of the return type of the base class method.

/**
 * 协变返回类型
 * @author Administrator
 *
 */
public class CovariantReturn {
    public static void main(String[] args) {
        Mill m = new Mill();
        Grain g = m.process();
        System.out.println(g);

         m = new WheatMill();
         g = m.process();
         System.out.println(g);
    }
}
class Grain{
    public String toString() {
        return "Grain";
    }
}
class Wheat extends Grain{
    public String toString() {
        return "Wheat";
    }
}
class Mill{
    Grain process(){
        return new Grain();
    }
}
class WheatMill extends Mill{
    Wheat process(){
        return new Wheat();
    }
}

8.5 Continuing Design with Inheritance

Compared to inheritance, composition mode is more flexible and can change object state at runtime.

/**
 * 状态模式
 * @author Administrator
 *
 */
public class Transmogrify {
    public static void main(String[] args) {
        Stage stage = new Stage();
        stage.performPlay();
        stage.change();
        stage.performPlay();
    }
}
class Actor{
    public void act() {}
}
class HappyActor extends Actor{
    public void act() {
        System.out.println("HappyActor");
    }
}
class SadActor extends Actor{
    public void act() {
        System.out.println("SadActor");
    }
}
class Stage{
    private Actor actor = new HappyActor();
    public void change() {
        actor = new SadActor();
    }
    public void performPlay() {
        actor.act();
    }
}

Type conversion is required during downcasting. If it does not exist, an exception will be thrown. This behavior of type checking during runtime is called runtime type checking.

Summarize:
write picture description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325421717&siteId=291194637
Recommended