上节学习了OOP的基本概念,接下来是对这些基本概念的具体实现方法的描述与理解,或许其中有些术语乍一听很难记,刚开始比较难理解,但配合着前面所学的概念去思考这些性质和原则的逻辑,就会发现这些概念不需要死记硬背,脑子一转就全明白了。
-
OOP的四种性质
- Encapsulation and information hiding 封装与信息隐藏
- Inheritance and overriding 继承与重写
- Polymorphism, subtyping and overloading 多态、子类型、重载
- *Static and Dynamic dispatch 静态与动态分派
具体概念在上一节中描述,不在此赘述,下文将对其具体实现进行阐述
-
封装--接口& 抽象类& 具体类
Concrete class(具体类) --> Abstract Class (抽象类)--> Interface (接口)
以上是逐层抽象化的过程
接口
定义ADT,只提供方法名,告知方法的作用(spec),不提供方法的实现。(Java8后可以在接口中实现方法,进一步加强了接口的能力,已经和抽象类的功能十分接近,但还存在区别)
- 接口之间可以继承与扩展
- 一个类可以实现多个接口(从而具备了多个接口中的方法)
- 一个接口可以有多种实现类
抽象类
- 要求:至少有一个抽象方法
- 抽象方法 Abstract Method:抽象方法是未被实现的,如果某些操作是所有子类型都共有,但彼此有差别,可以在父类型中设计抽象方法,在各子类型中重写。(此种方法和接口的功能有些类似)
具体类
实现ADT,要求实现父类的所有未实现的方法。
-
继承与重写
子类-->父类:继承(Inheritance)
类-->接口:实现(implement)、扩展
重写(Override)
对抽象类 / 接口中没有实现 / 已经实现的方法进行重新撰写,以此来完成方法的功能或者实现新的功能。
要求:
重写的函数要有完全一致的相同的名称、相同的参数或签名,以及相同的返回类型,这是与重载overload的区别所在,由于这些参数完全一致,所以静态检查不能检查出重写,而可以检查出重载,重写需要动态检查才知道调用的是哪一个方法,实际执行时调用哪个方法,运行时决定。
重写的时候不能改变原方法的本意,要遵守原方法的spec,原方法要求实现什么功能就得实现什么功能,在完成功能的基础上,可以用不同的方式改变实现的过程,但最终的输出要求要保证一致,就比如要求对一个数组排序,我们的spec要求的是输入一个无序数组,得到一个从大到小的数组。在接口中我们只需要写出sort(),知道其有为数组排序的功能即可,而在类中实现时可以使用冒泡、插入、快排、堆排序等不同的排序方法去实现。
而父类型中被重写的函数体如果是空的,即没有任何实现,则其所有子类型都需要这个方法,只是其内部实现不同。如果该函数体在父类中已经被实现,则该方法可以直接被复用,也可以对其重写实现子类的特殊要求。
严格继承:子类只能添加新方法,无法重写超类中的方法,子类只能向超类添加新方法,它无法覆盖它们——如果无法在Java程序中覆盖方法,则必须以关键字final作为前缀。
super:超类(父类)
- 重写之后,利用super复用了父类型中函数的功能,还可以对其进行扩展
- 如果是在构造方法中调用父类的构造方法,则必须在构造方法的第一行调用super()
- 用super的好处:可以不用知道父类叫什么名字,只需要使用super即可,或者说可以直接把super当成父类名字来进行方法的调用,很方便。
-
小结
学习至此,我们对于OOP的功能与实现有了一定的理解,并大概明白了该如何使用继承和重写(Override),其实光这一节学习只能明白在干什么,在学习了重载(Overload)后可能才会逐渐看得出其中的奥妙之处,软构软构,软件构造,我们不是敲代码机器,而是一个软件的构造者,我们是摩天大楼的设计师而不仅仅是搬砖工人,我们需要理解这种编程思想,并将其刻入脑海,才能在将来成为一名可靠的软件工程师。