Java8最有用的特性之一是接口上的新的default个方法.它们被引入的主要原因有两个(可能还有其他原因):

从API设计师的Angular 来看,我希望能够在接口方法上使用其他修饰符,例如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是一个班级,上述情况已经很常见了:

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);
}

现在,defaultfinal显然是相互矛盾的关键字,但是默认关键字本身是would not have been strictly required,所以我假设这个矛盾是故意的,以反映"class methods with body"(只是方法)和"interface methods with body"(默认方法)之间的细微差别,即我还没有理解的差别.

在某些时候,对接口方法上的staticfinal这样的修饰符的支持还没有得到充分探索,citing Brian Goetz:

另一部分是我们将在多大程度上支持班级建设

显然,自2011年底以来,接口中增加了对static个方法的支持.显然,这为JDK库本身增加了很多价值,比如Comparator.comparing().

问题:

为什么final个(以及static final个)从未实现Java8接口?

推荐答案

这个问题在某种程度上与What is the reason why “synchronized” is not allowed in Java 8 interface methods?有关

了解默认方法的关键是,主要设计目标是interface evolution,而不是"将接口变成(平庸的)特性".虽然两者之间有一些重叠,我们试图适应后者,而后者并没有妨碍前者,但从这个Angular 来看,这些问题最容易理解.(还要注意的是,类方法are将不同于接口方法,无论其意图如何,因为接口方法可以被多次继承.)

默认方法的基本思想是:它是带有默认实现的接口方法,派生类可以提供更具体的实现.因为设计中心是接口进化,所以一个关键的设计目标是能够以源代码兼容和二进制兼容的方式将默认方法添加到接口after the fact中.

对于"为什么不使用最终默认方法"这个问题,答案过于简单,因为这样一来,主体就不仅仅是默认的实现,而是唯一的实现.虽然这个答案有点过于简单,但它给了我们一个线索,即这个问题已经朝着一个值得怀疑的方向发展.

最终接口方法有问题的另一个原因是,它们给实现者带来了不可能的问题.例如,假设您有:

interface A { 
    default void foo() { ... }
}

interface B { 
}

class C implements A, B { 
}

在这里,一切都很好;CA继承foo().现在假设B更改为foo方法,默认值为:

interface B { 
    default void foo() { ... }
}

现在,当我们转到"重新编译C"时,编译器会告诉我们,它不知道要为foo()继承什么行为,所以C必须重写它(如果它想保留相同的行为,可以 Select 委托给A.super.foo())但如果B已经默认了final,而A不在《C》作者的控制之下呢?现在,C已经无法挽回地被打破;如果不重写foo(),它就无法编译,但如果foo()B年的最终版本,它就无法重写foo().

这只是一个例子,但重点是,方法的终结性在单继承类(通常是将状态与行为耦合起来的类)的世界中,实际上是一个更有意义的工具,而不是在仅贡献行为且可以多次继承的接口中.很难推理"最终实现者可能会混合哪些其他接口",而允许接口方法成为最终方法可能会导致这些问题(它们不会在编写接口的人身上爆发,而是在试图实现接口的可怜用户身上爆发)

不允许他们的另一个原因是他们的意思与你认为的不同.只有当类(或其超类)不提供方法的声明(具体或抽象)时,才会考虑使用默认实现.如果一个默认方法是final,但是一个超类已经实现了该方法,那么默认方法将被忽略,这可能不是默认作者在声明final时所期望的.(这种继承行为反映了默认方法的设计中心——接口进化.应该可以将默认方法(或现有接口方法的默认实现)添加到已有实现的现有接口中,在不改变实现接口的现有类的行为的情况下,保证在添加默认方法之前已经工作的类在存在默认方法时也能以同样的方式工作.)

Java相关问答推荐

编译期间错误(Java 0000)Android .Net MAUI

BiPredicate和如何使用它

如何将kotlin代码转换为java

为什么如果数组列表中有重复项,我的代码SOMETIMES不返回true?

将不受支持的时区UT重写为UTC是否节省?

使用Testcontainers与OpenLiberty Server进行集成测试会抛出SocketException

Spark上下文在向Spark提交数据集时具有内容,但Spark在实际构建它时发现它为空

为什么不应用类型推断?

内存中的H2修剪尾随空格

蒙蒂霍尔比赛结果不正确

如何让DTO接受空字符串字段,但如果它们不为空,则应用JPA验证?

我可以在MacOS上使用什么Java函数来在适当的设备上以适当的音量播放适当的alert 声音?

在Eclipse中调试未导出的JDK模块的Java包

try 在Android Studio中的infoWindow中使用EditText(Java)

对从Spring Boot 3.1.5升级到3.2.0的方法的查询验证失败

从12小时开始的日期模式

在整数列表中查找和可被第三个整数整除的对时出现无法解释的RunTimeError

Java KeyListener不工作或被添加

Java List有一个在一个位置添加多个元素的方法,但我找不到一个在一个位置删除多个元素的方法

谷歌应用引擎本地服务器赢得';t在eclipse上运行