2015-09-04 77 views
1

为什么我们需要在Java 8接口后卫方法,因为我们已经有抽象classes.I发现的各种答案,在互联网上,如:的Java 8极品

添加外部功能

但是抽象类是用于部分抽象的,因为我们的接口实际上是一个纯抽象类,所以为什么它们是接口中的默认方法?

+1

@Siguza这两种是同义词,而“默认”是官方的。 – dasblinkenlight

+0

通常的答案(这很容易找到)是他们需要将方法添加到像“Collection”这样的接口;没有默认的方法会破坏大量的第三方类,这些类会实现'collection'而不是新的方法。 – SJuan76

+0

@VGR不是一个骗局,但一个答案解释得很好 – SJuan76

回答

2

通过将功能放置在抽象基类中来共享功能的问题是一个类可以从一个基类派生。当您想从多个基地继承功能时,这是一个限制。

当您需要从已具有基类的类实现接口时,通过抽象基类共享功能也可能成为问题。在这种情况下,你根本无法派生你的新课程,因为你必须从两个基地中选择一个,当时你想要两个基地。

默认方法用优雅来解决这个问题:将您的通用实现置于默认方法中可让您无限制地共享代码。

你能想到的默认方法之间的主要区别和继承一个抽象类作为跨实现相同的接口,或者垂直从同一个基类继承的儿童的兄弟姐妹共享功能水平之间的差异。

这里是一个考试:考虑一个接口,看起来像JDBC的ResultSet,它有两种访问同一列的方式 - 按名称和索引。该接口可以被编码成这样:

interface ResultSet2 { 
    int findColumn(String columnLabel); 
    String getString(int index); 
    long getLong(int index); 
    default long getLong(String columnLabel) { 
     return getLong(findColumn(columnLabel)); 
    } 
    default String getString(String columnLabel) { 
     return getString(findColumn(columnLabel)); 
    } 
} 

任何实施ResultSet2必须实现三个方法,并获得剩下的两个是免费的。他们可以选择提供替代实施方案,但这是可选的。

+0

谢谢你的回答,我认为现在它清楚:) –

1

defender方法背后的主要原因是能够使用新功能扩展长期存在的接口,而不会破坏现有的代码。特别是在Java 8 lamba表达式中,他们在集合接口上引入了很多新方法,如Iterable.forEach。通过提供默认方法,实现Iterable接口的现有类不必更改为在Java 8环境中使用。

+0

你错了“没有打破现有的代码”。如果向接口添加一些已在某些实现类中定义的方法,并且这些方法与它们不兼容(例如它具有不同的结果类型),则会断开现有代码。你有没有听说过开放/封闭原则?当他们设计出如此厚的语言特性时,Brian Goetz和Oracle中的其他人肯定没有听说过它。 – mentallurg

1

最初的意图是与C#的扩展方法竞争。给定接口的核心方法,例如get(), set() in List,扩展方法(例如sort())可以被定义和实现。

Java人认为在接口本身而不是外部声明这样的方法会更好,以便这些方法可以被子类型覆盖,为每个子类型提供最佳的实现。 (他们也认为这样的方法应该由界面作者控制;这是一个软点)

虽然可以将默认方法添加到现有接口,但是破坏现有第三方子类型非常危险,特别是对于非常像List这样的旧类型在野外有许多亚型。因此很少有默认方法被添加到现有的核心Java API中。请参阅this question

对于新界面,默认方法对API设计人员来说是非常有价值的工具。您可以为接口添加许多便利方法,例如,Function.compose()。子类只需要实现抽象/核心方法,而不是默认方法(但如果他们想要的话,它们可以)。

我不同意默认方法可以“演化”接口的想法。它们不会更改接口的核心语义,它们只是便捷方法(以实例方法的形式)。

默认方法应该在设计接口时预先仔细设计;如上所述,之后添加默认方法是非常危险的。


C#的扩展方法允许第三方添加便捷方法;这是非常好的,没有理由说Java未来不会推出类似的东西。