Java 8允许在称为default methods的接口中默认实现方法。
我在什么时候使用那种接口默认方法,而不是抽象类(带有抽象方法)之间感到困惑。
那么什么时候应该使用默认方法的接口,什么时候应该使用抽象类(带有抽象方法)?抽象类在这种情况下仍然有用吗?
Java 8允许在称为default methods的接口中默认实现方法。
我在什么时候使用那种接口默认方法,而不是抽象类(带有抽象方法)之间感到困惑。
那么什么时候应该使用默认方法的接口,什么时候应该使用抽象类(带有抽象方法)?抽象类在这种情况下仍然有用吗?
当前回答
在Java 8中,接口看起来像一个抽象类,尽管它们可能有一些不同,例如:
1)抽象类是类,所以它们不受Java中接口的其他限制,例如抽象类可以有状态,但在Java中你不能在接口上有状态。
2)带有默认方法的接口和抽象类之间的另一个语义区别是,你可以在抽象类中定义构造函数,但在Java中你不能在接口中定义构造函数
其他回答
正如在其他回答中提到的,添加实现到接口的能力是为了在Collections框架中提供向后兼容性。我认为,提供向后兼容性可能是向接口添加实现的唯一好的理由。
否则,如果您将实现添加到接口,那么您就违反了最初添加接口的基本规律。Java是一种单一继承语言,不像c++允许多重继承。接口提供了支持多重继承的语言所具有的类型优势,而不会引入多重继承所带来的问题。
更具体地说,Java只允许实现的单一继承,但它允许接口的多重继承。例如,以下是有效的Java代码:
class MyObject extends String implements Runnable, Comparable { ... }
MyObject只继承了一个实现,但它继承了三个契约。
Java传递了实现的多重继承,因为实现的多重继承带来了许多棘手的问题,这些问题超出了本文的讨论范围。添加接口是为了允许合约的多重继承(又名接口),而不存在实现的多重继承问题。
为了支持我的观点,这里引用了Ken Arnold和James Gosling在《Java编程语言》(第4版)一书中的一句话:
Single inheritance precludes some useful and correct designs. The problems of multiple inheritance arise from multiple inheritance of implementation, but in many cases multiple inheritance is used to inherit a number of abstract contracts and perhaps one concrete implementation. Providing a means to inherit an abstract contract without inheriting an implementation allows the typing benefits of multiple inheritance without the problems of multiple implementation inheritance. The inheritance of an abstract contract is termed interface inheritance. The Java programming language supports interface inheritance by allowing you to declare an interface type
Java接口中的默认方法支持接口演进。
对于现有的接口,如果希望在不破坏接口旧版本的二进制兼容性的情况下向其添加方法,有两个选择:添加默认方法或静态方法。实际上,添加到接口中的任何抽象方法都必须由实现该接口的类或接口来实现。
静态方法对于类来说是唯一的。默认方法对于类的实例是唯一的。
如果向现有接口添加默认方法,实现该接口的类和接口不需要实现它。他们可以
实现默认方法,它将覆盖已实现接口中的实现。 重新声明方法(没有实现),使其抽象。 什么都不做(然后简单地继承实现接口的默认方法)。
更多关于这个话题的信息请点击这里。
从业务用例上下文中,接口可用于定义特定的业务规则,其中抽象类将定义启动业务的公共结构。
假设某个企业所有者希望与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甚至在接口中提供了私有方法,可以用来封装提供默认实现的接口方法中使用的公共代码逻辑。
在Java 8中,接口看起来像一个抽象类,尽管它们可能有一些不同,例如:
1)抽象类是类,所以它们不受Java中接口的其他限制,例如抽象类可以有状态,但在Java中你不能在接口上有状态。
2)带有默认方法的接口和抽象类之间的另一个语义区别是,你可以在抽象类中定义构造函数,但在Java中你不能在接口中定义构造函数