基于继承的多态

继承是对于存在IS-A关系的类之间的一种关系,子类可以重用父类的属性和方法,此时比较关键的引用的类型和对象的类型是一致的,比如

Book book = new Book();

 这里两者的类型都是Book,可假如我有更多细致的分类,比如语文书,英文书,数学书,显然它们都是Book,可以理解成都继承Book类,但各自有各自的特点,比如语文书里都是古诗词,英文书各种hello world,数学书都是计算公式,可能外观看上去都是一样模子的书,但是一翻开就知道不一样了,就好比通过翻这个动作就能够识别各种类型的书,可以理解为父类引用了不同的子类,也就是多态的概念

Book c = new ChineseBook();
Book e = new EnglishBook();
book m = new MathsBook();

具体更详细的含义,网上有段话描述的挺好:

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性

这里说的内容挺多,结合上面几行代码,可以得知父类类型的引用变量指向了子类类型的对象,说明首先肯定有继承关系,而引用是父类引用指向子类对象,也就是说只需要通过一个父类就能引用许多个不同的子类,还有一点就是方法的覆盖,这几点构成了多态的要素

看一段简单的代码

class Book {
    void chinese() {}
    void english() {}
    void maths() {}
}

class ChineseBook extends Book {
    void chinese() {
        System.out.println("A chinese book");
    }
}

class EnglistBook extends Book {
    void english() {
        System.out.println("A english book");
    }
}

class MathsBook extends Book {
    void maths() {
        System.out.println("A maths book");
    }
}

public class Main {
    public static void main(String[] args) {
        Book[] books = new Book[3];
        books[0] = new ChineseBook();
        books[1] = new EnglistBook();
        books[2] = new MathsBook();
        for (int i = 0; i < books.length; i++) {
            books[i].chinese();
            books[i].english();
            books[i].maths();
        }
    }
}

通过一个指向对象数组的引用books来分别调用子类的方法,显得十分轻盈,这里子类的方法覆盖掉了父类的同名方法,虽然books[i]是Book类型,但XXXBook都是Book的子类,说到底也都是Book类型,因此这样引用的方式是没问题的,但是引用指向的具体对象的类型却是由new对象的时候构造方法决定的

上面的执行结果就是:

A chinese book
A english book
A maths book

对象数组的元素全部都是指向子类对象的父类引用,而调用的子类里的方法在父类里全部都有,因此全部重写,最终调用的是子类里的方法而打印输出;理解方法可以是指向子类的父类引用,类型是父类的,子类继承父类,因此子类可以自动转型为父类,来赋值给这个引用,如此一来,它就只能使用父类中的方法和属性,而子类中独有的方法和属性引用是无法使用的;但如果子类重写了父类中的某些方法,在调用这些方法时,就会调用子类中的方法

更具体来说:

1:父类里的方法,如果子类里重写了该方法,那么父类类型的引用调用该方法将会调用子类中的这个方法

2:父类里的方法,如果子类中没有进行重写,那么父类类型的引用调用该方法将会调用父类中的这个方法

3:父类中没有而子类中有的方法,父类类型的引用是无法调用该方法的

比如这里给父类方法加一个打印

class Book {
    void chinese() {
        System.out.print("A chinese book in Book, ");
    }
    void english() {}
    void maths() {}
}

class ChineseBook extends Book {
    void chinese() {
        System.out.println("A chinese book");
    }
}

class EnglistBook extends Book {
    void english() {
        System.out.println("A english book");
    }
}

class MathsBook extends Book {
    void maths() {
        System.out.println("A maths book");
    }
}

public class Main {
    public static void main(String[] args) {
        Book[] books = new Book[3];
        books[0] = new ChineseBook();
        books[1] = new EnglistBook();
        books[2] = new MathsBook();
        for (int i = 0; i < books.length; i++) {
            books[i].chinese();
            books[i].english();
            books[i].maths();
        }
    }
}

这里的输出结果

A chinese book
A chinese book in Book, A english book
A chinese book in Book, A maths book

对于ChineseBook,chinese()覆盖掉了父类的方法,因此打印子类方法输出;而i=1和2的时候,由于子类没有覆盖chinese()方法,因此调用父类chinese()方法输出前半部分,然后调用子类相应方法输出后半部分

再进行一个打乱

class Book {
    void chinese() {
        maths();
    }
    void english() {
        chinese();
    }
    void maths() {
        System.out.println("maths from Book");
    }
}

class ChineseBook extends Book {
    void chinese() {
        System.out.println("A chinese book");
    }
}

class EnglistBook extends Book {
    void english() {
        System.out.println("A english book");
    }
}

class MathsBook extends Book {
    void maths() {
        System.out.println("A maths book");
    }
}

public class Main {
    public static void main(String[] args) {
        Book[] books = new Book[3];
        books[0] = new ChineseBook();
        books[1] = new EnglistBook();
        books[2] = new MathsBook();
        books[0].chinese();
        books[1].english();
        books[2].maths();
    }
}

输出结果为:

A chinese book
A english book
A maths book

从这个例子可以深深滴地看到,引用调用方法全部都是来自子类重写覆盖的方法,而和父类的方法没任何关系,但父类里这些方法必不可少,否则无法编译通过

总之多态能够让同一种行为有多种表现形式

发表回复