Java 8 最有用的特性之一是default接口上的新方法。引入它们的原因基本上有两个(可能还有其他原因):
default
Iterator.remove()
Iterable.forEach()
从 API 设计者的角度来看,我希望能够在接口方法上使用其他修饰符,例如final. 这在添加便捷方法时很有用,可以防止实现类中的“意外”覆盖:
final
interface Sender { // Convenience method to send an empty message default final void send() { send(null); } // Implementations should only implement this method void send(String message); }
Sender如果是一个类,以上已经是常见的做法:
Sender
abstract class Sender { // Convenience method to send an empty message final void send() { send(null); } // Implementations should only implement this method abstract void send(String message); }
现在,default和final显然是矛盾的关键字,但默认关键字本身并不是严格要求的,所以我假设这种矛盾是故意的,以反映 “类方法与主体” (只是方法)和 “接口”之间的细微差别 带有主体的方法”(默认方法),即我尚未理解的差异。
在某些时候,还没有完全探索对接口方法等修饰符的支持,static引用Brian Goetz的话:final
static
另一部分是我们将在接口中支持类构建工具的程度,例如最终方法,私有方法,受保护方法,静态方法等。答案是:我们还不知道
自 2011 年底以来,显然static增加了对接口方法的支持。显然,这为 JDK 库本身增加了很多价值,例如Comparator.comparing().
Comparator.comparing()
是什么原因final(也是static final)从未进入 Java 8 接口?
static final
了解默认方法的关键是主要设计目标是 接口进化,而不是“将接口变成(平庸)特征”。虽然两者之间有一些重叠,我们试图适应后者而不妨碍前者,但从这个角度来看,这些问题是最好的理解。(还要注意,无论意图如何,类方法 都将不同于接口方法,因为接口方法可以被多重继承。)
默认方法的基本思想是:它是一个具有默认实现的接口方法,派生类可以提供更具体的实现。而且因为设计中心是接口进化,所以一个关键的设计目标是能够在 事后 以源代码兼容和二进制兼容的方式将默认方法添加到接口中。
“为什么不是最终的默认方法”的过于简单的答案是,那么主体将不仅仅是默认实现,它将是唯一的实现。虽然这个答案有点过于简单,但它为我们提供了一个线索,即问题已经朝着一个值得怀疑的方向发展。
最终接口方法有问题的另一个原因是它们给实现者带来了不可能的问题。例如,假设您有:
interface A { default void foo() { ... } } interface B { } class C implements A, B { }
在这里,一切都很好;C继承foo()自A。现在假设B更改为具有foo默认值的方法:
C
foo()
A
B
foo
interface B { default void foo() { ... } }
现在,当我们重新编译时C,编译器会告诉我们它不知道要继承什么行为foo(),所以必须重写它(如果它想保留相同的行为C,可以选择委托给它。)但是如果已经默认了,是不是在作者的控制之下?现在已经无可挽回地破碎了;如果不覆盖它就无法编译,但如果它是 final in则无法覆盖。 A.super.foo()``B``final``A``C``C``foo()``foo()``B
A.super.foo()``B``final``A``C``C``foo()``foo()``B
这只是一个例子,但关键是方法的最终确定性实际上是一种工具,它在单继承类(通常将状态与行为耦合)的世界中比仅贡献行为并且可以成倍增加的接口更有意义遗传。很难推断“最终实现者中可能会混入哪些其他接口”,并且允许接口方法成为最终方法可能会导致这些问题(而且它们不会在编写接口的人身上爆炸,而是在试图实现它的可怜的用户。)
不允许它们的另一个原因是它们不会像您认为它们的意思一样。仅当类(或其超类)不提供方法的声明(具体或抽象)时才考虑默认实现。如果默认方法是最终方法,但超类已经实现了该方法,则默认方法将被忽略,这可能不是默认作者在声明它为最终方法时所期望的。(这种继承行为反映了默认方法的设计中心——接口进化。应该可以将默认方法(或现有接口方法的默认实现)添加到已经有实现的现有接口,而无需更改实现接口的现有类的行为,