gex*_*ide 119 java interface java-8 default-method
默认方法是我们的Java工具箱中一个不错的新工具.但是,我尝试编写一个定义default该toString方法版本的接口.Java告诉我这是禁止的,因为声明的方法java.lang.Object可能不会被default编辑.为什么会这样?
我知道存在"基类永远胜利"规则,因此默认情况下(pun;),方法的任何default实现Object都会被方法覆盖Object.但是,我认为没有理由说明Object规范中的方法不应该有例外.特别是对于toString具有默认实现可能非常有用.
那么,Java设计者决定不允许default方法覆盖方法的原因是什么Object?
Bri*_*etz 173
这是另一个语言设计问题,看起来"显然是一个好主意",直到你开始挖掘,你意识到它实际上是一个坏主意.
这封邮件有很多关于这个主题(以及其他主题).有几种设计力量融合在一起,使我们达到当前的设计:
AbstractList变成一个接口),你会发现继承equals/hashCode/toString与单继承和状态紧密相关,接口是多重继承和无状态的;你已经触及了"保持简单"的目标; 继承和冲突解决规则设计得非常简单(类胜过接口,派生接口胜过超接口,任何其他冲突都由实现类解决.)当然这些规则可以调整为异常,但是我认为当你开始使用该字符串时,你会发现增量复杂性并不像你想象的那么小.
当然,有一定程度的好处可以证明更复杂,但在这种情况下它并不存在.我们在这里讨论的方法是equals,hashCode和toString.这些方法本质上都是关于对象状态的,它是拥有状态而不是接口的类,它最有能力确定该等级对于该类的意义(特别是对于相等的契约非常强;请参阅有效Java有一些令人惊讶的后果); 接口编写器太远了.
拉出这个AbstractList例子很容易; 如果我们可以摆脱AbstractList并将行为放入List界面,那将是可爱的.但是,一旦你超越了这个明显的例子,就没有很多其他好的例子可以找到.在root中,AbstractList是为单继承而设计的.但接口必须设计为多重继承.
此外,假设您正在编写此类:
class Foo implements com.libraryA.Bar, com.libraryB.Moo {
// Implementation of Foo, that does NOT override equals
}
Run Code Online (Sandbox Code Playgroud)
该Foo作家着眼于超类型,认为没有实现平等的,并得出结论,得到参考平等,所有他所要做的就是继承等于Object.然后,下周,Bar"帮助"的库维护者添加了一个默认equals实现.哎呀!现在,语义Foo已被另一个维护域中的接口破坏,"有用"地为常用方法添加默认值.
默认值应该是默认值.将缺省值添加到没有的接口(层次结构中的任何位置)不应该影响具体实现类的语义.但是如果默认值可以"覆盖"Object方法,那就不是真的.
因此,虽然它看起来像一个无害的功能,但它实际上是非常有害的:它为很少的增量表达性增加了很多复杂性,并且它使得单独编译的接口的好意,无害的改变太容易破坏实现类的预期语义.
给出一个非常迂腐的答案,只禁止default为来自 的公共方法定义方法java.lang.Object。有 11 种方法可供考虑,可分为三种方式来回答这个问题。
Object方法不能有default方法,因为它们final根本不能被重写:getClass()、notify()、notifyAll()、wait()、wait(long)和wait(long, int)。Object方法不能有方法: 、和。defaultequals(Object)hashCode()toString()其中两个Object方法可以有default方法,尽管这种默认值充其量是有问题的:clone()和finalize()。
public class Main {
public static void main(String... args) {
new FOO().clone();
new FOO().finalize();
}
interface ClonerFinalizer {
default Object clone() {System.out.println("default clone"); return this;}
default void finalize() {System.out.println("default finalize");}
}
static class FOO implements ClonerFinalizer {
@Override
public Object clone() {
return ClonerFinalizer.super.clone();
}
@Override
public void finalize() {
ClonerFinalizer.super.finalize();
}
}
}
Run Code Online (Sandbox Code Playgroud)