JDK1.8 中 接口和抽象类的异同
在最新版本Java1.8中的变化里, Stephen Colebourne 告诉Hartmut Schlosser,“我认为最重要的语言上的改变不是Lambdas表达式,而是在接口上的静态和默认方法”。ColeBoune补充道,“默认方法功能的增加减少了许多使用抽象类的原因”。当我读到这里时,我意识到Colebourne是正确的,而且我通常用抽象类的许多场景可以通过JDK1.8的默认方法(default method)替换为JDK1.8接口。
在网上论坛和博客中讨论Java接口和抽象类异同的例子不胜枚举。这些讨论包括但不限于, JavaWorld 's Abstract classes vs. interfaces , StackOverflow 's When do I have to use interfaces instead of abstract classes? , Difference Between Interface and Abstract Class , 10 Abstract Class and Interface Interview Questions Answers in Java , 作为曾经有用的信息,许多现在已经过时了,可能会成为让Java体验更加混乱的部分。
在我思考Java1.8中接口和抽象类尚存在的不同,我决定去看看Java Tutorial关于这部分说过的信息。这个引导(Tutorial)已经更新到JDK 8 而且关于抽象方法和类的讨论有一个章节,称作 抽象类 vs 接口。这个章节指出在JDK 8 中接口和抽象类的异同点。着重强调的不同点是数据成员和方法的作用域(访问权限):
- 抽象类允许非静态和非final的域,允许方法成为public,static和final
- 所有的接口方法本质为public的。
在Java Tutorial接着列出了许多应该考虑抽象类的场景,和许多应该考虑接口的场景。不出意料,这些源于前面提到的不同、分歧,主要处理你是否需要域和方法成为private,protected,non-static,或者 not-final(偏向抽象类),或者你需要把重点放在类型而不是考虑实现的能力(偏向接口)。
因为Java语序一个类实现多个接口但只能继承一个类,接口可能被视为有利于多继承的实现。多亏JDK 8 的默认方法,这些接口甚至能提供默认的实现。
那么,一个很自然的问题是:当一个类实现了两个接口,而这两个接口描述了一个具有相同特点的默认方法,Java怎么处理。答案是,这会报一个编译错误。这是一个屏幕截图,NetBeans8上运行报的这个错误。
编译报错结论
JDK 8 争议性的把抽象类的优点带给接口。造成的影响是今天有大量的抽象类通过默认方法可能被替换为接口。