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


91

在集合接口中,我找到了一个名为的方法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关键词,它是如何工作的?



Answers:


162

来自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中,我们必须通过覆盖冲突的方法来手动解决它:

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();
    }
}

18
谢谢,真的很好。在我有机会问之前,您已经回答了我所有的问题。
杰夫·哈钦斯

为什么不使用抽象代替呢?
Astolfo Hoscher,

1
@AstolfoHoscher您只能扩展一个类,但是可以实现多个接口。
查尔斯·伍德

49

这些方法称为默认方法。默认方法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 2013年

2
@AniketThakur。在Java 8之前不允许这样做。此功能仅在Java 8中添加。您可以避免在实现类中提供默认方法的实现。
罗希特·贾因

1
@PawanMishra。看到我以前的评论。不,您不需要在实现类时提供默认接口方法的实现。
罗希特·简

1
@PawanMishra您可以覆盖它。没有限制,例如您只需要使用默认实现。
Aniket Thakur 2013年

4
向前迈出的一步,最终将避免被多重继承所困扰!
Xtreme Biker 2014年

17

我做了一些研究,发现了以下内容。希望这可以帮助。

存在的问题

普通的接口方法被声明为抽象的,并且必须在实现该接口的类中进行定义。这“负担”了类实现者的责任,以实现每个声明的方法。更重要的是,这也意味着在“发布”之后不可能扩展接口。否则,所有实现者都必须调整其实现,破坏源代码和二进制兼容性的向后。

Java 8中采用的解决方案

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

注意事项

  1. 实现者可以选择在实现类时不实现默认方法。
  2. 实现者仍然可以覆盖默认方法,例如可以在子类中覆盖常规的非最终类方法。
  3. 抽象类甚至可以将默认方法声明为抽象方法,从而迫使子类重新实现该方法(有时称为“重新抽象”)。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.