专注于Java领域优质技术,欢迎关注
作者:阿杜的世界 javaadu
在Java中可以用接口和抽象类来定义允许有多个实现的类型;不过,接口和抽象类有两个主要的不同:
在实际开发中,我们应该遵循一个原则——接口优于抽象类,主要是由于接口有三个方面的优势:
Java中的抽象类
抽象类的设计理念介于普通的类与接口之间,抽象类的目标是为了设计一个通用的、允许有多个实现的类型。
包含抽象方法的类叫做抽象类;抽象类无法实例化,如果一个类继承了某个抽象类,并且想实例化,就需要实现抽象类中的所有抽象方法。
抽象类在Java中的应用,最经典的是“骨架模式”——和接口配合使用,让设计同时具备抽象类和接口的优点——抽象类的演变比接口的演变要容易,同时允许系统中的其他类不使用这个骨架实现类。
在“骨架模式”中,接口的作用仍然是定义类型,骨架实现类就是一个抽象类,负责所有与接口实现相关的工作。集合框架中大量应用了“骨架模式”,例如:AbstractCollection、AbstractList、AbstractMap和AbstractSet,将一些通用的操作都放在骨架实现类中实现,这样具体的ArrayList和LinkedList就可以专注于自己的特性的实现,避免写重复代码。
“骨架模式”听起来有点像设计模式中的模板方法,不过二者之间还是有不一样的:“骨架模式”的目标是从代码层面避免重复代码,“模板方法”的目标是在设计层面对某一类事情的抽象和扩展点的设计。
Java中的接口
在Java中接口的语义是“is like”——任何实现了某个接口的类,看起来就像具备了这个接口的能力。
在Java中,接口可以用来做三个事情:
不过在《Effective Java》的第19条指出,接口应该只用于定义类型。
在Java8之前,接口中只能出现方法的声明,不能出现方法的实现。Java 8对接口的能力做了增强:
1.
Java 8中引入default method最主要的动机是:在Java 8中要支持lambda表达式,这就需要对原来JDK中的很多接口做修改,但是由于接口的特性(其实现类必须实现接口中声明的所有方法)的限制,如果直接修改,就会导致现有的Java应用在升级到Java 8的时候全部编译报错——这是不可接受的。
在实际开发中,对于default method的使用你可以注意几个点:
2
跟default method类似,static method也可以在接口中实现,但是你在使用过程中不能覆盖static method,因此,如果有些方法你不希望被具体的实现类破坏,就可以将之声明为static method。
在实际开发中,对于static method的使用你可以注意几个点:
3
为了支持lambda表达式,Java 8引入了一个新的注解:
@FunctionalInterface //方法注解
如果某个接口被这个注解修饰,这个接口就会被称为函数式接口。函数式接口注解不是必须的,但是是一种好的实践。
如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。。