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

Rav*_*avi 80 java default interface java-8

Java中的接口类似于类,但接口的主体只能包含抽象方法final字段(常量).

最近,我看到了一个问题,看起来像这样

interface AnInterface {
    public default void myMethod() {
        System.out.println("D");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

另一方面,当我试图写下面的代码时,它说 modifier default not allowed here

default class MyClass{

}
Run Code Online (Sandbox Code Playgroud)

代替

class MyClass {

}
Run Code Online (Sandbox Code Playgroud)

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

Ell*_*sch 61

这是Java 8中的一个新功能,它允许interface提供实现.在Java 8 JLS-13.5.6中描述.读取的接口方法声明(部分)

添加default方法,或从一个改变方法abstract,以default不破坏兼容性与预先存在的二进制文件,但可能会导致IncompatibleClassChangeError如果一个预先存在的二进制尝试调用的方法.如果符合条件的类型,出现此错误T,是的两个接口的子类型,I并且J,其中两个IJ声明一个default具有相同签名和结果的方法,既不I也不J是另一个的子接口.

JDK 8中的新功能(部分)

默认方法允许将新功能添加到库的接口,并确保与为这些接口的旧版本编写的代码的二进制兼容性.

  • @jWeaver接口和类之间的区别减少到_state_ vs _behavior_.接口可以携带行为,但只有类可以具有状态.(字段,构造函数和equals/hashCode等方法是关于状态的.) (14认同)
  • 看来,现在界面和抽象类几乎相同.:) (13认同)
  • @jWeaver接口仍然不能有构造函数,字段,私有方法或equals/hashCode/toString的实现. (13认同)
  • @Louis Wasserman:在Java 9中,他们可以使用`private`方法. (10认同)
  • @Dan Pantry:`private`方法实际上不是接口的一部分,但可以作为`default`实现的辅助方法或在常量初始化器中.请注意,它们已经存在于Java 8中,因为当您在接口中使用lambda表达式时,会生成合成的`private`方法.因此,Java 9允许您将该功能用于非合成,非lambda用途...... (6认同)
  • @LouisWasserman 是正确的,我们仍然有一些区别:) 我只是告诉我们我们离抽象类越来越近了。;) (2认同)
  • 对我来说,通过允许一个类从多个基类扩展,Java 似乎越来越接近 C++ 的问题。 (2认同)

spr*_*ter 21

Java 8中添加了默认方法,主要是为了支持lambda表达式.设计师(巧妙地,在我看来)决定使用lambdas语法来创建接口的匿名实现.但鉴于lambdas只能实现单一方法,它们将限制为使用单一方法的接口,这将是一个非常严格的限制.相反,添加了默认方法以允许使用更复杂的接口.

如果你需要对default由于lambdas引入的声明有所说服,请注意,Mark Reinhold在2009年提出的关于Project Lambda的许多提议,提到"扩展方法"作为强制性功能添加到支持lambdas.

这是一个展示这个概念的例子:

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);
Run Code Online (Sandbox Code Playgroud)

非常做作我意识到但应该说明如何default支持lambdas.因为inverse是默认值,所以如果需要,可以通过实现类轻松覆盖它.

  • 这不是真的正确.Lambdas可能是最直接的原因,但它们确实只是打破骆驼背部的稻草.真正的动机是启用_interface evolution_(允许现有接口兼容地进化以支持新行为); lambdas可能是将这种需求放在首位的因素,但这个特征比这更为普遍. (6认同)
  • 也许该文档会有所帮助:http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html。第10节明确指出:“默认方法(以前称为虚拟扩展方法或防御者方法)的目的是使接口在首次发布后能够以兼容的方式演进。” 然后,将Lambda友好方法作为界面演化的例证。 (2认同)
  • @BrianGoetz 为什么需要 _default_ 关键字?如果接口中的方法前面没有 _static_ 关键字并且有主体(大括号而不是分号),我们不能让编译器推断它是默认方法而不是抽象或静态方法吗? (2认同)
  • @Kartik您问的是错误的问题!我们不会基于“编译器正确解析程序所需的绝对最小值是多少”来选择语法;我们基于“将使读者的程序员的意图更直接地体现给读者的理由”来选择它。我们首先为用户设计,然后为编译器设计(涉及到用户时,我们首先为阅读而设计,其次是为编写。) (2认同)

Sau*_*aur 14

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

 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();
      }
   }
Run Code Online (Sandbox Code Playgroud)

输出是:

Do Some
在接口中的DoSomeOtherWork 类实现中实现

  • 我们不需要覆盖。这是关键点。这有助于我避免使用新函数编辑 N 个文件。谢谢你的例子! (3认同)
  • 问题:当直接父类实际上是一个接口时,@Override 注解会做什么?这对于 Interfaces 的第一个孩子来说是必需的吗? (2认同)

Mak*_*oto 10

在其他答案中忽略的一点是它在注释中的作用.早在Java 1.5之前,该default关键字就是为注释字段提供默认值的一种方法.

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

随着Java 8的引入,它的使用过载,允许用户在接口中定义默认方法.

其他被忽略的东西:声明default class MyClass {}无效的原因是由于类的声明方式.该语言中没有允许该关键字出现在那里的规定.但它确实出现在接口方法声明中.


小智 5

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

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

在 Java 8 中,我们可以通过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();
      }
   }
Run Code Online (Sandbox Code Playgroud)