本文将对jdk1.8以后的接口和抽象类进行讨论,假定读者已经了解java中接口(interface)和抽象类(abstract class)的基础定义和使用方法。
Java8以后接口的变更
Java 8接口的static method,让接口可以声明并实现多个静态方法,这一实现跟工具类的用途极为相似(工具类常用名为Utils,里面只有常用的静态方法,方便被其他类调用);
Java 8新增default method,让接口中可以包含方法的实现。
关于Java 8接口的变化细节可以参考文章 :
Java 9中,接口再次增强,可以实现private method和private static method。
看到这里,我们会发现Java9以后,在代码实现层面接口和抽象类的差别越来越小了,只剩下了构造器、成员变量以及单继承。接口可以多继承而抽象类只能单继承是最重要的区别。
Java9以后接口和抽象类的选择
Java9以后接口和抽象类的选择问题,我们主要从程序设计角度进行考虑,接口和抽象类还是有明显区分的:
子类和抽象类是is-a(是不是)关系;子类和接口是like-a(有没有)关系。
接口定义是为了在不同的模块/组件之间制定协议或契约。接口通常是在模块或组件中为了被外部的消费者调用而提前定义好的。
抽象类在设计上的主要目标之一是复用,子类作为父类的子集,从而可以复用父类的某些逻辑,包括属性(或者说状态)和行为。个人觉得抽象类不是一个很必要的东东。只有当开发者特别在意代码质量与架构设计、希望尽量少地向下级用户暴露封装好的信息时,抽象类才能起到关键的作用。
在这里,还是使用我之前文章中提到的那个门的例子来方便大家理解:
门应该设计为抽象类,因为所有的门都有开门和关门两个功能。不同种类的门(它们都是门,包括:普通锁门,电子锁门,以及带有警报功能的门),他们开门的实现方式不同,而关门的实现方式一致。因此设计为:
public abstract class Door {
public abstract void open();
public void close(){
System.out.println("门一关就锁上了!");
}
}
这样一来不同种类的门继承Door后就可以复用父类的close()方法,而重写字节的open()方法。而关于报警这一功能,我们应该给他设计为接口而不是抽象类中的抽象方法。原因很简单,不是所有的门都有报警功能,这是典型的like-a(有没有)的关系。因此设计为:
public class AlarmDoor extends Door implements IAlarm 即可(省略其他代码)。
最后的总结
单单从语法角度来看,java8以后,接口和抽象类越来越像了!但是当我们思考一个抽象方法该放在抽象类还是接口中时,那么只要简单判断这个抽象方法是否会被子类用多态来调用,就可以简单分类。牢记文章中的实例,不同的门,开门的方式是不同的,所以门应该设计为抽象类而不是接口!
网友评论