Java基础

Java编程思想笔记8.多态

2018-11-09  本文已影响2人  卢卡斯哔哔哔

点击进入我的博客

在面向对象的程序设计语言中,多态是继数据抽象(封装)和继承之后的第三种基本特征。
多态通过分离做什么怎么做,从另一角度将接口和实现分离开来。
多态的作用是消除类型之间的耦合关系。

8.1 再论向上转型

对象既可以作为它自己的本类使用,也可以作为它的基类使用。

8.1.1 忘记对象类型

我们只写一个简单的方法,它接受基类作为参数,而不是那些特殊的导出类。

public class Test {
    public static void main(String[] args) {
        func(new Unicycle());
        func(new Bicycle());
        func(new Tricycle());
    }

    public static void func(Cycle cycle) {
        cycle.ride();
    }
}

class Cycle {
    void ride() {}
}

class Unicycle extends Cycle {
    void ride() {
        System.out.println("Unicycle");
    }
}

class Bicycle extends Cycle {
    void ride() {
        System.out.println("Bicycle");
    }
}

class Tricycle extends Cycle {
    void ride() {
        System.out.println("Tricycle");
    }
}

8.2 转机

func(Cycle cycle)接受一个Cycle引用,那么编译器怎么才能知道这个Cycle引用指的是哪个具体对象呢?实际上,编译器并不知道。

8.2.1 方法调用绑定

8.2.2 产生正确的行为

在编译时,编译器不需要获得任何特殊信息就能进行正确的调用。

Cycle cycle = new Tricycle();
cycle.ride();

8.2.3 可扩展性

一个良好的OOP程序中,大多数或所有方法都会遵循基类的模型,而且只与基类接口通信。
这样的程序是可扩展的,因为可以从通用的基类继承出新的数据类型。
多态是一项让程序员“将改变的事物与未变的事物分离开来”的重要技术。

8.2.4 缺陷:“覆盖私有方法”

public class Test {
    public static void main(String[] args) {
        Test test = new TestDemo();
        test.func();
        // Output: Test
    }

    private void func() {
        System.out.println("Test");
    }
}

class TestDemo extends Test {
    public void func() {
        System.out.println("TestDemo");
    }
}

8.2.5 缺陷:域和静态方法

8.3 构造器和多态

构造器不具有多态性,因为它们也是隐式声明为static

8.3.1 构造器的调用顺序

对象调用构造器顺序

8.3.2 继承与清理

8.3.3 构造器内部的多态方法的行为

如果在构造器的内部调用正在构造的对象的某个动态绑定方法,会发生什么情况?

初始化的实际过程:
  1. 在其他任何事情发生之前,将分配给对象的存储空间初始化成二进制的零。
  2. 如8.3.1中那样调用基类构造器。因为在基类构造器中调用了func(),其实是被覆盖的func()方法。
  3. 按照声明的顺序调用成员的初始化方法。
  4. 调用导出类的构造器主体。
public class Test {
    public static void main(String[] args) {
        new Child(100);
    }
}

class Child extends Parent {
    private int i;
    void func() {
        System.out.println("Child func, i = " + i);
    }

    public Child(int i) {
        this.i = i;
        System.out.println("Before Child constructor, i = " + i);
        func();
        System.out.println("After Child constructor, i = " + i);
    }
}

class Parent {
    void func() {
        System.out.println("Parent func");
    }

    public Parent() {
        System.out.println("Before Parent constructor");
        func();
        System.out.println("After Parent constructor");
    }
}
Output:
Before Parent constructor
Child func, i = 0
After Parent constructor
Before Child constructor, i = 100
Child func, i = 100
After Child constructor, i = 100
编写构造器准则:

8.4 协变返回类型

子类覆盖(重写)父类的方法时,可以返回父类返回类型的子类。
这是JSE 5之后增加的功能,如下所示。Child中的func()返回的是父类返回类型List的子类ArrayList

class Child extends Parent {
    @Override
    ArrayList func() {
        return null;
    }
}

class Parent {
    List func() {
        return null;
    }
}

8.5 用继承进行设计

准则:用继承表达行为间的差异,用字段表达状态上的变化。

8.5.1 纯继承与扩展

纯继承
扩展

8.5.2 向下转型与运行时类型识别(RTTI)

上一篇下一篇

猜你喜欢

热点阅读