Why is “final” not allowed in Java 8 interface methods?
Java 8最有用的特性之一是接口上的新的EDCOX1 0种方法。引入它们的原因主要有两个(可能还有其他原因):
- 提供实际的默认实现。示例:
Iterator.remove() 。 - 允许JDK API的发展。示例:
Iterable.forEach()
从API设计器的角度来看,我希望能够在接口方法上使用其他修饰符,例如
1 2 3 4 5 6 7 8 9 10 | 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); } |
如果
1 2 3 4 5 6 7 8 9 10 | 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); } |
现在,
在某些时候,对接口方法上的修改器(如
The other part is how far we're going to go to support class-building
tools in interfaces, such as final methods, private methods, protected
methods, static methods, etc. The answer is: we don't know yet
显然,自2011年底以来,在接口中增加了对
EDOCX1的3个原因(EDCOX1?12)为何没有达到Java 8接口的原因是什么?
这个问题在某种程度上与Java 8接口方法中不允许"同步"的原因有关。
理解默认方法的关键是,主要的设计目标是接口的进化,而不是"将接口变成(平庸的)特性"。虽然两者之间有一些重叠,我们试图适应后者,但后者并没有妨碍前者,从这个角度来看,这些问题是最好理解的。(也请注意,类方法将不同于接口方法,无论其意图如何,因为接口方法可以被多次继承。)
默认方法的基本思想是:它是具有默认实现的接口方法,派生类可以提供更具体的实现。由于设计中心是接口进化的,所以在设计完成后,可以将默认方法以源代码兼容和二进制兼容的方式添加到接口中是一个关键的设计目标。
对"为什么不最终默认方法"的回答太简单了,那就是主体将不再只是默认的实现,而是唯一的实现。虽然这个答案有点太简单,但它告诉我们这个问题已经朝着一个可疑的方向发展了。
最后的接口方法值得怀疑的另一个原因是它们为实现者创造了不可能的问题。例如,假设您有:
1 2 3 4 5 6 7 8 9 | interface A { default void foo() { ... } } interface B { } class C implements A, B { } |
这里一切都很好,以东十一〔0〕从以东十一〔2〕继承了以东十一〔1〕。假设
1 2 3 | interface B { default void foo() { ... } } |
现在,当我们重新编译
这只是一个例子,但关键是,最终的方法实际上是一个工具,在单一继承类(通常是将状态与行为耦合)的世界中,比只贡献行为并可以被多次继承的接口更有意义。很难解释"哪些其他接口可能会混入最终实现者",并且允许一个接口方法成为最终方法可能会导致这些问题(这些问题不会在编写该接口的人身上爆炸,而是在尝试实现该接口的糟糕用户身上爆炸)。
不允许他们的另一个原因是他们不是你认为他们的意思。只有当类(或其超类)不提供方法的声明(具体或抽象)时,才会考虑默认实现。如果一个默认方法是final,但是一个超类已经实现了该方法,那么默认值将被忽略,这可能不是默认作者在声明final时所期望的。(这种继承行为反映了默认方法的设计中心——接口演进。应该可以向已有实现的现有接口添加默认方法(或现有接口方法的默认实现),而不更改实现该接口的现有类的行为,确保在添加默认方法之前已经工作的类将以相同的方式工作。在存在默认方法的情况下。)
在lambda邮件列表中有很多关于它的讨论。其中一个似乎包含了很多关于所有这些东西的讨论的是:在不同的接口方法可见性上(是最终的防御者)。
在本次讨论中,原始问题的作者Talden提出了与您的问题非常相似的问题:
The decision to make all interface members public was indeed an
unfortunate decision. That any use of interface in internal design
exposes implementation private details is a big one.It's a tough one to fix without adding some obscure or compatibility
breaking nuances to the language. A compatibility break of that
magnitude and potential subtlety would seen unconscionable so a
solution has to exist that doesn't break existing code.Could reintroducing the 'package' keyword as an access-specifier be
viable. It's absence of a specifier in an interface would imply
public-access and the absence of a specifier in a class implies
package-access. Which specifiers make sense in an interface is unclear
- especially if, to minimise the knowledge burden on developers, we have to ensure that access-specifiers mean the same thing in both
class and interface if they're present.In the absence of default methods I'd have speculated that the
specifier of a member in an interface has to be at least as visible as
the interface itself (so the interface can actually be implemented in
all visible contexts) - with default methods that's not so certain.Has there been any clear communication as to whether this is even a
possible in-scope discussion? If not, should it be held elsewhere.
最终布莱恩·戈茨的回答是:
Yes, this is already being explored.
However, let me set some realistic expectations -- language / VM
features have a long lead time, even trivial-seeming ones like this.
The time for proposing new language feature ideas for Java SE 8 has
pretty much passed.
所以,很可能它从未被实现,因为它从来都不是范围的一部分。从来没有及时提出要考虑的建议。
布赖恩在另一场关于最后一名防守队员方法的激烈讨论中说:
And you have gotten exactly what you wished for. That's exactly what
this feature adds -- multiple inheritance of behavior. Of course we
understand that people will use them as traits. And we've worked hard
to ensure that the the model of inheritance they offer is simple and
clean enough that people can get good results doing so in a broad
variety of situations. We have, at the same time, chosen not to push
them beyond the boundary of what works simply and cleanly, and that
leads to"aw, you didn't go far enough" reactions in some case. But
really, most of this thread seems to be grumbling that the glass is
merely 98% full. I'll take that 98% and get on with it!
因此,这强化了我的理论,即它不是范围的一部分,也不是设计的一部分。他们所做的就是提供足够的功能来处理API演进的问题。
对于@ejp评论中提到的答案,很难找到并确定"答案":世界上大约有2个(+/-2)人可以给出明确的答案。而令人怀疑的是,答案可能只是"支持最终违约方法似乎不值得重组内部呼叫解决机制"。当然,这是推测,但至少有一些微妙的证据支持,比如OpenJDK邮件列表中的这一声明(由两个人中的一个人提供):
"I suppose if"final default" methods were allowed, they might need rewriting from internal invokespecial to user-visible invokeinterface."
当一个方法是一个
更进一步的真正的"作者"信息确实很难找到,即使有过多的网页搜索和通过阅读提交日志。我认为这可能与使用
我不认为有必要在方便的接口方法上指定
无论哪种方法,您都应该为默认方法编写适当的javadoc,精确地显示该方法是什么,不允许做什么。这样,实现接口的类"不允许"更改实现,尽管没有保证。
任何人都可以编写一个依附于接口的