Java 8允许在称为default methods的接口中默认实现方法。

我在什么时候使用那种接口默认方法,而不是抽象类(带有抽象方法)之间感到困惑。

那么什么时候应该使用默认方法的接口,什么时候应该使用抽象类(带有抽象方法)?抽象类在这种情况下仍然有用吗?


当前回答

抽象类比默认方法实现(如私有状态)要多得多,但从Java 8开始,无论何时您可以选择其中任何一种,都应该选择防御器(也就是私有状态)。默认)方法。

默认方法的限制是它只能通过调用其他接口方法来实现,而不能引用特定实现的状态。所以主要的用例是高级和方便的方法。

这个新特性的好处在于,以前您必须使用抽象类来实现方便的方法,从而将实现者限制为单一继承,现在您可以拥有一个真正干净的设计,只需要接口,并且强制程序员进行最少的实现工作。

向Java 8引入默认方法的最初动机是希望在不破坏任何现有实现的情况下,使用面向lambda的方法扩展集合框架接口。虽然这与公共图书馆的作者更相关,但您可能会发现相同的特性在您的项目中也很有用。您有一个集中的地方可以添加新的便利,而不必依赖于类型层次结构的其余部分。

其他回答

在Java 8中,接口看起来像一个抽象类,尽管它们可能有一些不同,例如:

1)抽象类是类,所以它们不受Java中接口的其他限制,例如抽象类可以有状态,但在Java中你不能在接口上有状态。

2)带有默认方法的接口和抽象类之间的另一个语义区别是,你可以在抽象类中定义构造函数,但在Java中你不能在接口中定义构造函数

有一些技术上的差异。与Java 8接口相比,抽象类仍然可以做更多的事情:

抽象类可以有构造函数。 抽象类更加结构化,可以保存状态。

从概念上讲,防御方法的主要目的是在Java 8中引入新特性(如lambda-functions)后实现向后兼容性。

Remi Forax规则是不要用抽象类进行设计。你用界面来设计你的应用。无论Java的版本是什么,无论语言是什么。它以SOLID原理中的界面分离原理为依据。

稍后您可以使用抽象类来分解代码。现在有了Java 8,你可以直接在界面中完成。这只是个设施,仅此而已。

从业务用例上下文中,接口可用于定义特定的业务规则,其中抽象类将定义启动业务的公共结构。

假设某个企业所有者希望与Amazon和Walmart合作,那么这里定义的接口将是WalmartPartner, AmazonPartner将定义特定的业务规则,抽象类BusinessSetup将获得特定区域的业务设置。

// Interfaces
 
public interface WalmartPartner {
    public static boolean signUpForWalmartBusinessAccount(String BusinessId){
        System.out.println("Setting up Walmart Business Partner");
        return true;
    }
    public default  void  getWalmartDeals(){
        System.out.println("Default walmart deal executed !");
    }
    public abstract void setupShopifyForWalmart();
    public abstract  void setupWalmartProducts();

public interface AmazonPartner {
    public static boolean signUpAsAmazonServicePartner(String BusinessId){
        System.out.println("Setting up Amazon Business Partner");
        return true;
    }
    public default  void  paymentPlatformSetup(){
        System.out.println(" Amazon default payment platform is setup");
    }
    public abstract void setupPrimeMemberDealsByRegion();
    public abstract  void setupPrimeDeals();
}

 // Abstract class 

public abstract class BusinessSetup {
    String businessId ;
    public BusinessSetup(String businessId){
        this.businessId = businessId;
        System.out.println("1. Initial Business setup for BusienssID: "+this.businessId+" is Complete");
    }
    public final boolean getBusinessRegisteredInRegion(String region){
        System.out.println("2. Business got registered in "+region+ "!");
        return true;
    }
    public abstract void setupCustomerPlatform(String customerId);
    public abstract void setupVendorPlatform(String vendorId);

}

// Concrete Class 
public class WalMartPartnerImpl extends BusinessSetup implements WalmartPartner {
    public WalMartPartnerImpl(String businessId) {
        super(businessId);
    }
    @Override
    public void setupCustomerPlatform(String customerId) {
    }

    @Override
    public void setupVendorPlatform(String vendorId) {
    }

    @Override
    public void setupShopifyForWalmart() {
    }

    @Override
    public void setupWalmartProducts() {
    }
    public static void main(String args[]){
        WalMartPartnerImpl walMartPartner = new WalMartPartnerImpl("wal8989");
        walMartPartner.getBusinessRegisteredInRegion("california");
        walMartPartner.getWalmartDeals();
        walMartPartner.setupCustomerPlatform("wal8989");

    }
}

每当我们在抽象类和接口之间做出选择时,我们总是(几乎)选择默认方法(也称为防御器或虚拟扩展)。

Default methods have put an end to classic pattern of interface and a companion class that implements most or all of the methods in that interface. An example is Collection and AbstractCollection. Now we should implement the methods in the interface itself to provide default functionality. The classes which implement the interface has choice to override the methods or inherit the default implementation. Another important use of default methods is interface evolution. Suppose I had a class Ball as: public class Ball implements Collection { ... }

现在在Java 8中引入了一个新特性流。我们可以通过使用添加到接口的stream方法来获取流。如果stream不是默认方法,那么Collection接口的所有实现都将中断,因为它们不会实现这个新方法。向接口添加非默认方法与源不兼容。

但是假设我们不重新编译这个类,而是使用一个包含这个类Ball的旧jar文件。如果没有这个缺失的方法,类将很好地加载,可以创建实例,似乎一切都在正常工作。但是如果程序在Ball实例上调用stream方法,我们将得到AbstractMethodError。因此,使方法默认解决了这两个问题。

Java 9甚至在接口中提供了私有方法,可以用来封装提供默认实现的接口方法中使用的公共代码逻辑。