面向对象引入了类的概念,即将相似的事物抽象出来形成模板,用于后续事物的创建。那么有没有相似的类,将相似的类进行抽象呢?这样就可以定义相似的类,实现更高层次的代码复用,Java提供了抽象类和接口的概念。
1. 抽象类
1.1 抽象类的基本介绍
类和类之间具有共同特征,将这些共同特征提取出来,形成的类就是抽象类。注意,抽象级别:对象 < 类 < 抽象类。因为对象是实际存在的,所以类可以实例化;但是因为类本身是不存在的,仅仅是抽象出的一个概念,所以抽象类无法实例化(无法创建对象)成类,抽象类也属于引用数据类型。
抽象类是在类的基础上进一步提取共有特征而抽象出来的,对对象进行抽象形成类,对类进行抽象则形成抽象类。换句话说,对抽象类也可进一步抽象。注意,类和抽象类在现实世界中是不存在的,对象则是现实世界中实际存在的。

抽象类的定义语法:
1 | [修饰符列表] abstract class 类名{ |
- 抽象类是无法实例化的,主要用来被子类继承。抽象类可以继承抽象类,仍然是抽象类。
- 因为抽象类是用来继承的,所以abstract不能和final关键字一起使用,会报错:非法的修饰符组合。
- 抽象类虽然无法实例化,但是有构造方法,这个构造方法是供子类使用的。因为继承,子类创建对象的时候,会默认有super()方法,就是默认调用父类的构造方法。
- 抽象类中的一个概念:抽象方法。抽象类中可以没有抽象方法,但抽象方法必须出现在抽象类中。所以,非抽象子类必须实现父类的抽象方法,否则,因为子类也会继承父类的抽象方法,如果抽象方法没有实现(覆盖、重写)的话,这就是普通类中有抽象方法了。
- 抽象类也可以实现多态,抽象父类指向非抽象子类对象。
1.2 抽象方法
抽象方法只能存在抽象类中,表示没有实现的方法。该方法没有方法体(即没有大括号),修饰符列表中有abstract关键字,语法结构如下:
1 | [修饰符列表] abstract 返回值类型 方法名(); |
抽象类多态代码案例如下所示:
1 | // 抽象类 |
注意,问题:Java语言中凡是没有方法体的方法都是抽象方法?
不对,是错误的,Object类中就有很多方法都没有方法体,都是以”;”结尾的,但他们都不是抽象方法,例如
public native int hashCode();,这个方法就是底层调用了c++写的动态链接库程序。前面修饰符列表中没有abstract,有一个native。表示调用 JVM本地程序。
2. 接口
抽象类中既有抽象方法也有非抽象方法,并且存在构造方法,并不是完全抽象,那么此时结构上可能就不是很清晰。可不可以将其完全抽象呢?Java提供了接口的概念。
2.1 接口的基本介绍
接口是完全抽象的,而抽象类则是半抽象的,或者也可以说接口是特殊的抽象类。接口也是一种引用数据类型,和抽象类一样,编译后生成.class文件。接口的基本语法如下:
1 | [修饰符列表] interface 接口名{ |
接口可以继承,支持多继承。一个接口可以继承多个接口,一个类可以实现多个接口,弥补了单继承带来的缺陷。
接口中只包含两部分内容:常量和抽象方法。不包含其他的普通方法。
接口中所有的元素都是public修饰的,即都是公开的。既然接口中都是抽象方法,并且都有public,所以实际上public和abstract是可以省略的,系统会自动加上。
同上,变量都是常量,所以public、static、final也是可以省略的,系统会自动加上。
类和类之间叫做继承extends,类和接口之间叫做实现implements。
抽象类也可以实现接口,但是非抽象类实现接口,必须实现接口里的所有方法。(因为接口里的方法都是抽象的,如果不实现的话,那这就是抽象方法存在于非抽象类中了)
注意,类在实现接口方法的时候,一定要注意修饰符列表,因为在接口中是默认加public和abstract的,而在类中,是不会加上的,所以要手动加上public。
接口也是一种类,可以使用多态。
继承和实现都存在的话?要先继承,再实现。就是extends要在implements的前面。
1
class Cat extends Animal implements Flyable{}
注意,之前提到过,每个类都是默认继承Object的,那么如果我们只是实现了某个接口,底层实际上是先继承Object类的,如下所示:
1
2
3class Fish implements Flyable{}
// 底层实际上是这样的
class Fish extends Object implements Flyable{}
2.2 接口在开发中的作用
接口在开发中的作用,类似于多态在开发中的作用。多态的作用:面向抽象编程,不要面向具体编程。降低程序的耦合度,提高程序的扩展力。
简单案例如下:
1 | public class Master{ |
接口:接口是纯抽象的,面向抽象编程,可以认为是面向接口编程。可以降低程序的耦合度,提高程序的扩展力。符合OCP开发原则。另外,接口是将两侧给解耦合了,一侧是调用接口的方法,另一侧是实现接口。即其中一侧只负责调用接口的方法,另一侧只要按照要求实现接口的方法即可。根据多态,接口类型引用指向实现接口类的对象。所以接口相当于解耦合了。
所以,接口的作用就是解耦合。当然,除了解耦合,另一个作用就是代码复用了。
2.3 抽象类和接口有什么区别?
只说一下二者在语法上的区别。
- 抽象类是半抽象的,接口是完全抽象的。
- 抽象类中有构造方法,接口中没有构造方法。
- 接口和接口之间支持多继承。类和类之间只能单继承。
- 一个类可以同时实现多个接口,一个抽象类只能继承一个类。
- 接口中只允许出现常量和抽象方法。接口使用的比抽象类多。
- 接口一般都是对行为的抽象。
- 接口的祖先也是Object类。
3. 类型之间的关系
目前介绍到的类型有方法/属性、对象、类、接口(抽象类)。四者的关系如下:
is a
is a表示的是“继承关系”,即类之间的继承关系。
has a
has a表示的是“关联关系”,即类有某些属性/方法。
like a
like a表示的是“实现关系”,类实现接口。
4. 简单案例
1 | interface Eating{ |
5. 备注
参考B站《动力节点》。