当前位置: 首页 > 面试题库 >

为什么Java 8接口方法中不允许使用“最终”?

任小云
2023-03-14
问题内容

Java 8最有用的功能之一是default接口上的新方法。引入它们的原因基本上有两个(可能还有其他原因):

  • 提供实际的默认实现。例:Iterator.remove()
  • 允许JDK API演进。例:Iterable.forEach()

从API设计人员的角度来看,我希望能够在接口方法上使用其他修饰符,例如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);
}

现在,default并且final显然是相互矛盾的关键字,但是默认关键字本身并没有严格要求,因此我假设这种矛盾是有意的,以反映 “带有主体的类方法” (正义方法)和 “接口
之间的细微差别。 带主体的方法” (默认方法),即我尚未理解的差异。

在一定的时间点,对于像修饰符的支持staticfinal接口方法上还没有充分探讨,援引布赖恩戈茨:

另一部分是我们要在接口中支持类构建工具的程度,例如最终方法,私有方法,受保护的方法,静态方法等。答案是:我们尚不知道

从2011年底开始,很明显,static增加了对接口方法的支持。显然,这为JDK库本身增加了很多价值,例如with
Comparator.comparing()

题:

是什么原因final(也static final没有)没有使用Java 8接口?


问题答案:

这个问题在某种程度上与Java8接口方法中不允许“同步”的原因有关?

了解默认方法的关键是,主要的设计目标是 接口演变
,而不是“将接口转变为(中等)特性”。虽然两者之间存在一些重叠,并且我们试图适应后者所没有的障碍,但是从这种角度来看,最好理解这些问题。(还要注意,由于接口方法可以被多重继承的事实,无论什么意图,类方法
将与接口方法不同。)

默认方法的基本思想是:它是具有默认实现的接口方法,而派生类可以提供更具体的实现。而且由于设计中心是接口的演进,因此一个关键的设计目标是能够在 事后
以源兼容和二进制兼容的方式将默认方法添加到接口。

对于“为什么不是最终的默认方法”的答案太简单了,那就是主体将不再仅仅是默认的实现,而是唯一的实现。尽管答案太简单了,但它为我们提供了一个线索,表明这个问题已经朝着可疑的方向发展了。

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

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

interface B { 
}

class C implements A, B { 
}

在这里,一切都很好。C继承foo()A。现在假定B已更改为具有foo默认值的方法:

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

现在,当我们进行重新编译时C,编译器将告诉我们它不知道要继承什么行为foo(),因此C必须重写它(并且A.super.foo()如果希望保留相同的行为,可以选择委托给它。)但是如果B已经违约了final,并且A不受作者的控制C吗?现在C已经无法挽回了。它不能不覆盖就进行编译foo(),但是foo()如果它是final
in 则不能覆盖B

这只是一个例子,但重点是方法的确定性实际上是一种工具,在单继承类(通常将状态与行为耦合)的世界中,比仅对行为做出贡献且可以相乘的接口更有意义。遗传。很难说出“最终实现器中可能还混入了其他什么接口”,而允许接口方法成为最终方法可能会导致这些问题(它们不会对编写接口的人大发雷霆,而会炸毁该接口的人)。尝试实施该功能的可怜用户。)

禁止使用它们的另一个原因是,它们不会代表您的意思。仅当类(或其超类)未提供方法的声明(具体或抽象)时,才考虑使用默认实现。如果默认方法是final方法,但是超类已经实现了该方法,则默认值将被忽略,这可能不是默认作者在声明它为final时所期望的。(此继承行为反映了设计中心对默认方法(接口演变)的反映。应该可以将默认方法(或对现有接口方法的默认实现)添加到已经具有实现的现有接口中,而无需更改实现该接口的现有类的行为,



 类似资料:
  • 我们举个例子: 一个常见的解决方案是转移到一个抽象类,但是在我的具体案例中,我有一个枚举的接口,所以在这里不适用。我想这不是被忽略了,就是因为接口背后的原始想法,即它们是可用方法的“契约”,但我想我需要关于这是怎么回事的输入。 我读过“为什么Java 8接口方法中不允许使用”final“?”,其中说: 默认方法的基本思想是:它是具有默认实现的接口方法,派生类可以提供更具体的实现 与关联问题一样,由

  • 虽然有些人曾经问过这个问题,但那是在Java8发布之前。 以前,静态成员是不允许的,因为实现细节不能在接口中定义。这也是为什么任何东西都不应该是私有的,因为接口的实现者需要提供实现细节。 Java8改变了这种情况,不是吗?默认方法定义实现细节,静态方法也是如此。那么,为什么仍然不允许这样做呢?

  • 问题内容: 为什么在Java 8中允许接口具有方法? 如下面的代码所述,它可以正常工作并正确产生输出。 目前它的行为就像一个类,我已经用main方法执行了。 我们为什么需要这个? 问题答案: 从Java 8开始,接口中允许使用静态方法。 main()是静态方法。 因此,在接口中允许main()。 我们 不需要 它,因为以前不允许这样做,但是我们幸存了下来。但是,根据定义,由于静态方法不是绑定到类的

  • 为什么Java不允许在接口中使用私有成员?有什么特别的原因吗?

  • 问题内容: 在Java 8中,我可以轻松地编写: 我将获得在类中也可以使用的完整同步语义。但是,我不能在方法声明上使用修饰符: 现在,可以争论说这两个接口的行为方式相同,只是在on 和on上建立了一个 契约 ,这比 契约 要强一点。当然,我们也可能会争辩说,实现不应对具体的实现状态做出任何假设,或者这样的关键字根本无法发挥作用。 题: JSR-335专家组决定不支持接口方法的原因是什么? 问题答案