Java 中 default 关键字的用途是什么?

What is the purpose of the default keyword in Java?

An interface in Java is similar to a class, but the body of an interface can include only abstract methods and final fields (constants).

最近看到一道题目,大概是这样的

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}

根据接口定义,只允许使用抽象方法。为什么它允许我编译上面的代码? default 关键字是什么?

另一方面,当我尝试编写以下代码时,它显示 modifier default not allowed here

default class MyClass{

}

而不是

class MyClass {

}

谁能告诉我 default 关键字的用途?它只允许在界面内使用吗?它与 default(无访问修饰符)有何不同?

这是 Java 8 中的一项新功能,它允许 interface 提供实现。在 Java 8 JLS-13.5.6. Interface Method Declarations 中描述(部分)

Adding a default method, or changing a method from abstract to default, does not break compatibility with pre-existing binaries, but may cause an IncompatibleClassChangeError if a pre-existing binary attempts to invoke the method. This error occurs if the qualifying type, T, is a subtype of two interfaces, I and J, where both I and J declare a default method with the same signature and result, and neither I nor J is a subinterface of the other.

What's New in JDK 8 说(部分)

Default methods enable new functionality to be added to the interfaces of libraries and ensure binary compatibility with code written for older versions of those interfaces.

默认方法使您能够向应用程序的界面添加新功能。它也可以用来拥有多重继承。 除了默认方法之外,您还可以在接口中定义静态方法。这使您更容易组织辅助方法

Java8 中引入了一个新概念,称为默认方法。默认方法是那些具有一些默认实现并有助于在不破坏现有代码的情况下改进接口的方法。让我们看一个例子:

public interface SimpleInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword

    default public void doSomeOtherWork() {
        System.out.println("DoSomeOtherWork implementation in the interface");
    }
}

class SimpleInterfaceImpl implements SimpleInterface {

    @Override
    public void doSomeWork() {
        System.out.println("Do Some Work implementation in the class");
    }

    /*
    * Not required to override to provide an implementation
    * for doSomeOtherWork.
    */

    public static void main(String[] args) {
        SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
        simpObj.doSomeWork();
        simpObj.doSomeOtherWork();
    }
}

输出为:

   Do Some Work implementation in the class
   DoSomeOtherWork implementation in the interface

默认方法已添加到 Java8,主要是为了支持 lambda 表达式。设计者(在我看来很聪明)决定使用 lambdas 语法来创建接口的匿名实现。但是鉴于 lambda 只能实现一个单一的方法,它们将被限制为具有单一方法的接口,这将是一个非常严格的限制。相反,添加了默认方法以允许使用更复杂的接口。

如果您需要证明 default 是由于 lambda 表达式引入的说法,请注意 Mark Reinhold 在 2009 年的 Lambda 项目 straw man proposal 中提到了 'Extension methods'作为为支持 lambda 而添加的强制性功能。

下面是一个演示该概念的示例:

interface Operator {
    int operate(int n);
    default int inverse(int n) {
        return -operate(n);
    }
}

public int applyInverse(int n, Operator operator) {
    return operator.inverse(n);
}

applyInverse(3, n -> n * n + 7);

我意识到非常做作,但应该说明 default 如何支持 lambda。因为 inverse 是默认值,所以如果需要,它可以很容易地被实现 class 覆盖。

新的 Java8 功能 (Default Methods) 允许接口在标有 default 关键字时提供实现。

例如:

interface Test {
    default double getAvg(int avg) {
        return avg;
    }
}
class Tester implements Test{
 //compiles just fine
}

接口测试使用 default 关键字,它允许接口提供方法的默认实现,而无需在使用该接口的 class 中实现那些方法。

向后兼容性: 想象一下,您的接口由数百个 classes 实现,修改该接口将迫使所有用户实现新添加的方法,即使它对于实现您的接口的许多其他 classes 不是必需的。

事实与限制:

1-只能在接口内声明,不能在 class 或 摘要 class.

2-必须提供正文

3-它不被假定为 public 或像接口中使用的其他普通方法那样抽象。

The Java™ Tutorials中找到了很好的解释,部分解释如下:

考虑一个涉及计算机控制汽车制造商的示例,这些制造商发布行业标准接口,描述可以调用哪些方法来操作他们的汽车。如果那些由计算机控制的汽车制造商为他们的汽车添加新功能(例如飞行)会怎么样?这些制造商需要指定新的方法,使其他公司(例如电子制导仪制造商)能够将他们的软件应用于飞行汽车。这些汽车制造商将在哪里声明这些与飞行相关的新方法?如果他们将它们添加到原来的接口中,那么实现了这些接口的程序员将不得不重写它们的实现。如果他们将它们添加为静态方法,那么程序员会将它们视为实用方法,而不是必不可少的核心方法。

默认方法使您能够向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性。

其他答案中忽略的一点是它在注释中的作用。早在 Java 1.5 时,default 关键字就作为注释字段 provide a default value 的一种方式出现。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Processor {
    String value() default "AMD";
}

随着 Java 8 的引入,允许在接口中定义默认方法,重载 用法。

其他被忽略的事情:声明 default class MyClass {} 无效的原因是由于 classes are declared at all. There's no provision in the language that allows for that keyword to appear there. It does appear for interface method declarations 的方式。

接口中的默认方法允许我们在不破坏旧代码的情况下添加新功能。

在 Java8 之前,如果一个新方法被添加到一个接口,那么该接口的所有实现 类 都必须重写该新方法,即使它们没有使用新功能。

使用Java8,我们可以在方法实现之前使用default关键字为新方法添加默认实现。

即使使用匿名 类 或功能接口,如果我们发现某些代码是可重用的并且我们不想在代码中的所有地方定义相同的逻辑,我们可以编写这些代码的默认实现并重用他们。

例子

public interface YourInterface {
    public void doSomeWork();

    //A default method in the interface created using "default" keyword
    default public void doSomeOtherWork(){

    System.out.println("DoSomeOtherWork implementation in the interface");
       }
    }

    class SimpleInterfaceImpl implements YourInterface{

     /*
     * Not required to override to provide an implementation
     * for doSomeOtherWork.
     */
      @Override
      public void doSomeWork() {
  System.out.println("Do Some Work implementation in the class");
   }

 /*
  * Main method
  */
 public static void main(String[] args) {
   SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
   simpObj.doSomeWork();
   simpObj.doSomeOtherWork();
      }
   }