“默认”接口方法的实现是什么?

108

在集合接口中,我找到一个名为removeIf()的方法,其中包含其实现。


default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);  
    boolean removed = false;  
    final Iterator<E> each = iterator();   
    while (each.hasNext()) {  
        if (filter.test(each.next())) {  
            each.remove();  
            removed = true;  
        }  
    }  
    return removed;  
}  

我想知道是否有任何方法可以在接口中定义方法体?
什么是default关键字以及它是如何工作的?


3
请查看这篇关于默认方法的文章:http://zeroturnaround.com/rebellabs/java-8-explained-default-methods/#!/。 - emeraldjava
相关帖子 https://dev59.com/hFwZ5IYBdhLWcg3wVfAC - Ravi
3个回答

192

来源:https://dzone.com/articles/interface-default-methods-java

Java 8引入了“默认方法”或(Defender方法)新特性,允许开发人员向接口中添加新方法而不会破坏这些接口的现有实现。它提供了灵活性,允许接口定义实现,在具体类未提供该方法的实现时将其用作默认实现。

public interface A {
    default void foo(){
       System.out.println("Calling A.foo()");
    }
}

public class ClassAB implements A {
}

当人们第一次听到关于默认方法的新特性时,他们通常会问一个常见的问题:

如果一个类实现了两个接口,并且这两个接口定义了相同签名的默认方法,那么会发生什么?

以下是一个例子来说明这种情况:

public interface A {  
    default void foo(){  
        System.out.println("Calling A.foo()");  
    }  
}

public interface B {
    default void foo(){
        System.out.println("Calling B.foo()");
    }
}


public class ClassAB implements A, B {

}  

该代码无法编译,结果如下:

java: class Clazz inherits unrelated defaults for foo() from types A and B
为了解决这个问题,在 Clazz 中,我们需要通过覆盖冲突的方法来手动解决它:

要解决此问题,在 Clazz 中,我们必须手动覆盖冲突的方法:

public class Clazz implements A, B {
    public void foo(){}
}

但是如果我们想要调用接口A中默认的foo()方法而不是实现自己的方法怎么办。

可以通过以下方式引用A#foo():

public class Clazz implements A, B {
    public void foo(){
       A.super.foo();
    }
}

25
谢谢,非常好的阐述。您在我有机会提问之前就回答了我所有的问题。 - Jeff Hutchins
为什么不使用抽象类? - Astolfo Hoscher
2
@AstolfoHoscher 你只能继承一个类,但是你可以实现多个接口。 - Charles Wood

51

这些方法被称为默认方法。 默认方法 Defender方法是Java 8中新增的功能之一

它们将被用于允许接口方法提供一个默认实现,在具体类没有为该方法提供实现的情况下使用。

因此,如果您有一个带有默认方法的接口:

public interface Hello {
    default void sayHello() {
        System.out.println("Hello");
    }
}

以下的类是完全有效的:

public class HelloImpl implements Hello {

}

如果您创建了一个HelloImpl的实例:

Hello hello = new HelloImpl();
hello.sayHello();  // This will invoke the default method in interface

有用链接:


一个类实现接口但不实现它的方法,这样做可以吗?就我使用的Java7而言,是不允许这样做的。 - Aniket Thakur
2
@AniketThakur。在Java 8之前是不允许的。这个特性只在Java 8中添加了。您可以避免在实现类中提供default方法的实现。 - Rohit Jain
1
@PawanMishra。请查看我的先前评论。不需要在实现类中提供默认接口方法的实现。 - Rohit Jain
1
@PawanMishra 你可以覆盖它。没有限制,比如你必须只使用默认实现。 - Aniket Thakur
4
终于迈出了一大步,可以避免受到多重继承的困扰! - Aritz
显示剩余2条评论

20

我进行了一些调查,并找到了以下内容。希望这能帮到你。

现有问题

通常的接口方法被声明为抽象方法,并且必须在实现接口的类中定义。这会使得类实现者承担实现每个已声明方法的责任,更重要的是,这意味着在“发布”之后无法扩展接口。否则,所有实现者都必须适应其实现,破坏向后源和二进制兼容性。

Java 8采用的解决方案

为了解决这些问题,JDK 8的一个新特性是可以使用默认方法扩展现有接口。 默认方法不仅被声明,还在接口中定义。

需要注意的重要点

  1. 实现者可以选择不在实现类中实现默认方法。
  2. 实现者仍然可以覆盖默认方法,就像正常的非final类方法可以在子类中被覆盖一样。
  3. 抽象类甚至可以(重新)声明默认方法为抽象方法,强制子类重新实现该方法(有时称为“重新抽象化”)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接