1.第八章一开头就说了多态的作用:消除类型之间的耦合关系。
2.多态的前提是继承与重写,因为继承之后允许将子类视为自己本身或者当做其父类进行处理,当做其父类处理就涉及到了一个概念向上转型,而多个子类对其父类的某个方法重写,并将这些子类向上转型为父类,就使得父类持有不同子类的引用后再调用同一方法就能表现出不同的行为。
// Dog & Cat 均继承自 Animal 并已经重写过yell方法,即不同动物叫声也不同
Animal animal = new Dog();
animal.yell();
// animal 先持有狗的引用,调用重写后的叫声方法,输出为 汪汪
animal = new Cat();
animal.yell();
// animal 再持有猫的引用,调用重写后的叫声方法,输出为 喵~
3.向上转型:对某个对象的引用视为对其基类的引用。
// Dog 继承自 Animal
Animal animal = new Dog();
4.子类不可能比父类更“小”,因为继承那一刻就已经获取父类除了 private 之外的所有内容,而且还有个可能添加属于自己的独有功能。
5.多态也被成为动态绑定,后期绑定,运行时绑定。即通过某种机制,可以在运行时判断对象的类型,从而调用恰当的方法。
6.Java 除了 static 方法和 final 方法(private 方法属于 final 方法)之外, 其他所有方法都是动态绑定的,所以 final 关键是修饰方法其实也是有效的“关闭”了动态绑定。
7.为什么说多态是一项“将改变的事物与未变的事物分离开来”的重要技术,因为我们通过继承,向上转向,重写需要的方法,从而不断的拓展我的使用,未变的事物指的是基类,而改变的事物就是不断新拓展出来的之类,从而使得我在不改变的原有代码的基础上就可以实现新的功能,只需要我把子类引用赋给父类即可,这也是开闭原则和里氏替换原则的使用。
// 任何 Animal 子类都可以当做参数传递进来
public void animalYell(Animal animal) {
animal.yell();
}
animalYell(new Dog());
animalYell(new Cat());
8.只有非 private 方法才可以被覆盖。虽然我们可以在子类中定义与基类中 private 方法同名的方法,但这并不是重写。
9.静态方法是与类,而非与单个对象相关联的。
10.构造并不具有多态性,因为他们实际上是 static 的,只不过该 static 的声明是隐式的。
11.多态中的构造调用顺序是基类构造总是在导出类之前被调用,且按照继承层次组件向上,从而使得背个基类的构造都得到调用。
12.构造内使用多态的行为。
// 书中的例子
class Glyph {
void draw() {print("Glyph.draw()");}
Glyph() {
print("Glyph() before draw");
draw();
print("Glyph() after draw");
}
}
class RoundGlyph extends Glyph {
private int radius = 1;
RoundGlyph (int r) {
radius = r;
print("RoundGlyph.RoundGlyph(), radius = " + radius);
}
void draw() {
print("RoundGlyph.draw(), radius = " + radius);
}
}
new RoundGlyph(5);
// 输出结果如下
Glyph() before draw
// 这时候子类的radius还未获取到传递过来的值
RoundGlyph.draw(), radius = 0
Glyph() after draw
RoundGlyph.RoundGlyph(), radius = 5
13.如果多态,字段看左边(看基类),方法看右边(看具体实现类)。
14.所以多态意味着“不同的形式”,即通过继承,向上转型,方法重写,不同的实现类会体现会不同的形式,从而通过基类调用同一方法,使得我们只是调用了基类的方法却看到了不同形式的结果。
15.向上转型会丢失具体的类型信息,如果我们可以通过向下转型从而再次获得一个的具体信息。