目录
前言
对于面向对象编程来说,抽象是它的一大特征之一。在 Java 中,可以通过两种形式来体现 OOP 的抽象:接口和抽象类。这两者有太多相似的地方,又有太多不同的地方。今天我们就一起来学习一下Java中的接口和抽象类
一、抽象类
1.抽象类简介
抽象类不能用于实例化对象,抽象类往往用来表示抽象概念。
举个例子,中国人(Chinese 类)和美国人(American 类)都有“吃饭”这个行为,因此可以先定义一个 Person 类,然后让 Chinese 和 American 都继承这个类。但如何在父类 Person 中定义“吃饭”这个方法呢?一般而言,中国人是用筷子吃饭,并且吃的是中餐;而美国人是用刀叉吃饭,吃的是西餐,显然二者对于“吃饭”这一行为的具体实现是不同的。因此,无法在父类 Person 中具体的定义“吃饭”这一方法。此时,就可以将 Person 定义成一个抽象类,并将“吃饭”这个行为定义成抽象方法(只有方法声明,但没有方法体的方法),然后再在子类 Chinese 和 American 中分别对“吃饭”进行具体的实现。
2.抽象类的语法形式
在面向对象分析和设计的过程中,经过封装和继承的分析之后,可以先创建一个抽象的父类该父类定义了其所有子类共享的一般形式(如 Person 类),具体细节再由子类来完成(如 Chinese 类和 American 类)。
Java 中定义抽象类的语法形式: abstract class 类名{ }
3.抽象类的三个语法特征
1.抽象类不能被直接实例化
2.抽象类的子类必须实现抽象方法(除非这个子类也是抽象类)
3.抽象类里可以有普通方法,也可以有抽象方法,但是有抽象方法的类必须是抽象类。
抽象类里面也可以没有抽象方法,只是把原来的类前面加上 abstract 关键字,使其变为抽象类。
二、接口
1.接口简介
接口是一系列抽象方法的集合,与抽象类不同,不可以声明普通方法。
虽然有人常说,接口是一种特殊的抽象类,但是在面向对象编程的设计思想层面,两者还是有显著区别的。抽象类更侧重于对相似的类进行抽象,形成抽象的父类以供子类继承使用;而接口往往在程序设计的时候,定义模块与模块之间应满足的规约或者定义一种标准,使各模块之间能协调工作
2.接口的定义语法
[修饰符] interface 接口名 [extends] [接口列表]{ 接口体 }
interface 前的修饰符是可选的,如果使用修饰符,则只能用 public 修饰符,表示此接口是公有的,在任何地方都可以引用它,这一点和类是相同的。 接口是和类同一层次的,所以接口名的命名规则参考类名命名规则即可
extends 关键词和类语法中的 extends 类似,用来定义直接的父接口。和类不同,一个接口可以继承多个父接口,当 extends 后面有多个父接口时,它们之间用逗号隔开。
接口中不能有实体方法:
public interface EmailInterface { ... public void showEmail(){ } }
3.接口中的成员变量
接口中可以有成员变量,修饰符默认为 public static final(即便不写修饰符也默认是这样),因为是常量所以必须在声明时对这些成员变量赋初值
可以这样说,接口中的成员变量实际就是常量。接口中的抽象方法默认且必须是 public 的
4.接口的继承与合并
如果让一个类(Email)实现了多个接口(EmailInterface 和 PortInterface 接口),但是再在 EmailWriter 类的 writeEmail() 方法中传入对象时,形参就必须是这个类(Email),而不能是该类实现的某个接口。
根据多态的知识,多态对象只能调用定义该对象的类和其父接口中的方法,因此如果给 writeEmail() 方法设置的形参只是某一个接口(如 EmailInterface 接口)类型,那么该形参将无法调用其他接口(PortInterface 接口)中的方法。但如果将方法的参数类型设置为一个类而不是一个接口,这样做就不是我们推荐的面向接口编程了。
接口继承的方式解决上述问题,即用一个接口继承多个接口,从而实现接口合并的效果。
三、两者之间的区别
1.普通类可以实例化,接口都不能被实例化(它没有构造方法),抽象类如果要实例化,抽象类必须指向实现所有抽象方法的子类对象(抽象类可以直接实例化,直接重写自己的抽象方法),接口必须指向实现所有所有接口方法的类对象。
2.抽象类要被子类继承,接口要被子类实现。
3.接口只能做方法的声明,抽象类可以做方法的声明,也可以做方法的实现。
4.接口里定义的变量只能是公共的静态常量,抽象类中定义的变量是普通变量。
5.抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类的抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如果不能全部实现接口方法,那么该类只能是抽象类。
6.抽象方法只能声明,不能实现。接口是设计的结果,抽象类是重构的结果。
7.抽象类里可以没有抽象方法。
8.如果一个类里有抽象方法,那么该类只能是抽象类。
9.抽象方法要被实现,所以不能是静态的,也不能是私有的。
10.接口可以继承接口,并可多继承接口,但类只能单继承。(重要啊)
11.接口中的常量:有固定的修饰符-public static final(不能用private和protected修饰/本质上都是static的而且是final类型的,不管加不加static修饰)。
12.接口中的抽象方法:有固定的修饰符-public abstractv
总结
若果你拥有一些方法并且想让他们中的一些有默认实现,那就用抽象类。
如果你想实现多重继承,那么必须使用接口。由于 java 不支持多继承,子类不能继承多个父类,但是可以实现多个接口,因此你可以使用接口来实现它。
如果基本基本功能在不断变化,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么所有实现类都需要改变。