为什么我们需要Java中的默认方法?

2022-09-02 12:51:20

我正在查看与7相比的Java 8新闻,除了非常有趣的东西,如lambdas或新的时间框架,我发现引入了一个新的功能(?):默认方法

在本文中找到了以下示例:

public interface Math {

    int add(int a, int b);

    default int multiply(int a, int b) {
        return a * b;
    }
}

这对我来说似乎很奇怪。上面的代码看起来像一个具有已实现方法的类。那么,为什么要在接口中引入默认方法呢?这种方法的实际优势是什么?abstract

在同一篇文章中,我读到了这个解释:

为什么要将方法添加到接口中?这是因为接口与其实现类的耦合太紧密。也就是说,不可能在不破坏实现器类的情况下在接口中添加方法。在接口中添加方法后,其所有实现的类都必须声明此新方法的方法主体。

好吧,这根本不能说服我。恕我直言,我相信当一个类实现一个接口时,必须为它中的每个方法声明方法体。这当然是一个约束,但它也证实了它的“性质”(如果你理解我的意思......

如果每个继承类都有通用逻辑,则将其放入实现类中。abstract

那么,默认方法的真正优势是什么?(它看起来更像是一种解决方法,而不是新功能...)


更新我知道这种方法是为了向后兼容,但它仍然不能说服我太多。接口表示类必须具有的行为。因此,实现某个接口的类肯定具有此行为。但是,如果有人可以任意更改接口,则此约束已打破。行为可以随时改变...我错了吗?


答案 1

这是为了向后兼容。

如果你有一个其他人已经实现的接口,那么如果你向该接口添加一个新方法,那么所有现有的实现都会被破坏。

通过添加具有默认实现的新方法,您可以保持与现有实现的源兼容。

对于一个稍微简单/人为的例子,希望能够证明这一点,让我们假设你创建了一个库:

void drawSomething(Thing thing) {
}

interface Thing {
    Color getColor();
    Image getBackgroundImage();
}

现在你来做一个新版本的库,你想添加边框颜色的概念,这很容易添加到界面:

interface Thing {
    Color getColor();
    Color getBorderColor();
    Image getBackgroundImage();
}

但问题是,每个使用你的库的人都必须回顾他们曾经做过的每一个Skin实现,并添加这个新方法。

相反,如果您为刚刚调用的默认实现提供了一个默认实现,那么一切都“正常工作”。getBorderColorgetColor


答案 2

过去有很多方法可以在抽象界面上起作用。在Java 8之前,它们必须被放入一个额外的类中来配对接口,例如 跟。CollectionsCollection

这种旧方法既不比方法更有说服力,也不更实用。而不是你不得不说.这也意味着在创建 时必须做出基本决策,要么要求每个实现都实现一个方法,要么在实用程序类中提供一个不能被覆盖的方法。defaultlist.sort()Collections.sort(list)interfaceListsortsort

使用方法,您可以同时拥有两者,一个标准实现,实现本身不需要实现,但如果一个具体的实现有更有效的方法可以做到这一点,知道它的内部,例如 将其内部数组直接传递给跳过一些中间操作。defaultListArrayList.sortArrays.sort