Java8 : Why is it forbidden to define a default method for a method from java. lang.Object

标签 java interface java-8 default-method

默认方法是我们 Java 工具箱中一个不错的新工具。但是,我尝试编写一个接口(interface)来定义 toString 方法的 default 版本。 Java 告诉我这是被禁止的,因为在 java.lang.Object 中声明的方法可能不是 defaulted。为什么会这样?

我知道有“基类总是获胜”的规则,所以默认情况下(双关语;),任何 object 方法的 default 实现都将被覆盖Object 中的方法。但是,我认为规范中的 Object 方法不应该有异常(exception)。特别是对于 toString,有一个默认实现可能非常有用。

那么,Java 设计者决定不允许 default 方法覆盖 Object 方法的原因是什么?

最佳答案

这是另一个看起来“显然是个好主意”的语言设计问题,直到您开始挖掘并意识到它实际上是个坏主意。

This mail有很多关于这个主题(以及其他主题)。有几种设计力量汇聚在一起,将我们带到了当前的设计中:

  • 保持继承模型简单的愿望;
  • 事实上,一旦你回顾了明显的例子(例如,将 AbstractList 变成一个接口(interface)),你就会意识到继承 equals/hashCode/toString 与单一继承和状态以及接口(interface)密切相关是多重继承和无状态的;
  • 这可能会为一些令人惊讶的行为打开大门。

您已经触及“保持简单”的目标;继承和冲突解决规则被设计得非常简单(类胜过接口(interface),派生接口(interface)胜过超接口(interface),任何其他冲突都由实现类解决。)当然,这些规则可以调整为异常(exception),但是我想当你开始拉弦时你会发现,增量的复杂性并不像你想象的那么小。

当然,有一定程度的好处可以证明更复杂是合理的,但在这种情况下它不存在。我们这里讨论的方法是equals、hashCode和toString。这些方法本质上都是关于对象状态的,拥有状态的是类,而不是接口(interface),谁最有资格确定平等对那个类意味着什么(尤其是平等的契约非常强;参见有效Java 带来了一些令人惊讶的后果);界面编写者离得太远了。

AbstractList例子很容易拉出来;如果我们可以摆脱 AbstractList 并将行为放入 List 接口(interface)中,那就太好了。但是一旦你超越了这个明显的例子,就找不到很多其他好的例子了。从根本上讲,AbstractList 是为单一继承而设计的。但是接口(interface)必须为多重继承而设计。

进一步,假设你正在编写这个类:

class Foo implements com.libraryA.Bar, com.libraryB.Moo { 
    // Implementation of Foo, that does NOT override equals
}

Foo 作者查看父类(super class)型,没有看到 equals 的实现,并得出结论,要获得引用相等,他需要做的就是从 Object 继承 equals。然后,下周,Bar 的库维护者“有帮助地”添加了一个默认的 equals 实现。哎呀!现在 Foo 的语义已被另一个维护域中的接口(interface)破坏,“有用地”为常用方法添加了默认值。

默认值应该是默认值。向没有的接口(interface)(层次结构中的任何位置)添加默认值不应影响具体实现类的语义。但是,如果默认值可以“覆盖” Object 方法,那将是不正确的。

因此,虽然它看起来像是一个无害的特性,但实际上却是相当有害的:它增加了很多复杂性,只需要很少的增量表现力,而且它让善意的、看似无害的更改太容易单独编译接口(interface)破坏实现类的预期语义。

关于Java8 : Why is it forbidden to define a default method for a method from java. lang.Object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24016962/

相关文章:

java - 使用静态方法作为 JavaFX 更改监听器

java - 模块已被弃用并标记为删除

java - 由于 SpringBatc 中的 Chunk 计数而导致记录丢失

naming-conventions - 接口(interface)是否有 ISomething/ISomethingable 的替代方案?

c# - 需要实现属性的接口(interface)

java - 如何使用 java 8 流将 HashMap 的值设置为自定义 java 对象?

java - 立即从 Java 8 流的集合中返回一个值

java - 继承和 REST API Controller - 处理子类

javascript - 正则表达式可选捕获未按预期工作

vb.net - 如何在 VB.NET 中将接口(interface)属性设置为只读?