类的定义由访问控制级别、类型、类名、是否抽象、是否静态、泛型标识、继承或实现关键字、父类或接口名称等组成。Java类主要由两部分组成:成员和方法。
接口与抽象类
正如面向对象四大特性(抽象、封装、继承、多态)所述,定义类的过程就是抽象和封装的过程,而接口与抽象类则是对实体类进行更高层次的抽象,仅定义公共行为和特征。
接口与抽象类的共同点是都不能被实例化,但可以定义引用变量指向实例对象。
下面从语法上分析两者的不同之处:
序号 | 语法维度 | 抽象类 | 接口 |
1 | 定义关键字 | abstract | interface |
2 | 子类继承或实现关键字 | extends | implements |
3 | 方法实现 | 可以有 | 不能有,但在JDK8及以后,允许有default实现 |
4 | 方法访问控制符 | 无限制 | 有限制,默认是public abstract类型 |
5 | 属性访问控制符 | 无限制 | 有限制,默认是pubilc static final 类型 |
6 | 静态方法 | 可以有 | 不能有,但在JDK8及以后,允许有 |
7 | static{}静态代码块 | 可以有 | 不能有 |
8 | 本类型之间扩展 | 单继承 | 多继承 |
9 | 本类型之间扩展关键字 | extends | extends |
抽象类再被继承时体现的是is-a关系,接口再被实现时体现的是can-do关系。与接口相比,抽象类通常是对同类事物相对具体的抽象,通常包含抽象方法、实体方法、属性变量,如果一个抽象类只有一个抽象方法,那么它就等同于一个接口。
抽象类是模板式设计,而接口是契约式设计。
接口是顶级的“类”,虽然关键字是interface,但是编译之后的字节码扩展名还是.class。抽象类是二当家,接口位于顶层,而抽象类对各个接口进行了组合,然后实现部分接口行为。
Java语言中类的继承采用单继承形式,避免继承泛滥、菱形继承、循环继承等现象。在JVM中,一个类如果有多个直接父类,那么方法的绑定机制就会变得非常复杂。
接口继承接口,关键字是extends,而不是implements。允许多重继承,是因为接口有契约式的行为约定,没有任何具体实现和属性,某个实现类在实现多重继承后的接口时,只是说明“can do many things”。
当纠结定义接口还是抽象类时,优先推荐定义为接口,遵循接口隔离原则,按某个维度划分成多个接口,然后再用抽象类去implements某些接口,这样做可方便后续的扩展和重构。