簡體   English   中英

在 Java 中使用相同簽名的兩個默認方法實現兩個接口 8

[英]Implementing two interfaces with two default methods of the same signature in Java 8

假設我有兩個接口:

public interface I1
{
    default String getGreeting() {
        return "Good Morning!";
    }
}

public interface I2
{
    default String getGreeting() {
        return "Good Afternoon!";
    }
}

如果我想同時實現它們,將使用什么實現?

public class C1 implements I1, I2
{
    public static void main(String[] args)
    {
        System.out.println(new C1().getGreeting());
    }
}

這是一個編譯時錯誤。 你不能有來自兩個接口的兩個實現。

但是,如果您在C1實現getGreeting方法,這是正確的:

public class C1 implements I1, I2 // this will compile, bacause we have overridden getGreeting()
{
    public static void main(String[] args)
    {
        System.out.println(new C1().getGreeting());
    }

    @Override public String getGreeting()
    {
        return "Good Evening!";
    }
}

我只想補充一點,即使 I1 中的方法是抽象的,而 I2 中的默認方法,您也不能同時實現它們。 所以這也是一個編譯時錯誤:

public interface I1
{
    String getGreeting();
}

public interface I2
{
    default String getGreeting() {
        return "Good afternoon!";
    }
}

public class C1 implements I1, I2 // won't compile
{
    public static void main(String[] args)
    {
        System.out.println(new C1().getGreeting());
    }
}

這不是特定於問題的。 但是,我仍然認為它為上下文增加了一些價值。 作為@toni77 答案的補充,我想補充一點,可以從實現類調用默認方法,如下所示。 在下面的代碼中, interface I1的默認方法getGreeting()是從重寫的方法調用的:

public interface I1 {
     default String getGreeting() {
        return "Good Morning!";
     }
}

public interface I2 {
    default String getGreeting() {
        return "Good Night!";
    }
}

public class C1 implements I1, I2 {       
    @Override
    public String getGreeting() {
        return I1.super.getGreeting();
    }
}

如果一個類實現了 2 個接口,這兩個接口都有一個具有相同簽名的 java-8 默認方法(如您的示例中所示),則實現類必須覆蓋該方法 該類仍然可以使用I1.super.getGreeting();訪問默認方法I1.super.getGreeting(); . 它可以訪問其中之一,兩者都可以訪問,也可以都不訪問。 所以以下將是 C1 的有效實現

public class C1 implements I1, I2{
    public static void main(String[] args)
    {
        System.out.println(new C1().getGreeting());
    }

    @Override //class is obliged to override this method
    public String getGreeting() {
        //can use both default methods
        return I1.super.getGreeting()+I2.super.getGreeting();
    }

    public String useOne() {
        //can use the default method within annother method
        return "One "+I1.super.getGreeting();
    }

    public String useTheOther() {
        //can use the default method within annother method
        return "Two "+I2.super.getGreeting();
    }


}

有一種情況,根據解析規則,這實際上是有效的。 如果接口之一擴展了其他接口之一。

使用上面的例子:

public interface I2 extends I1 {
    default String getGreeting() {
        return "Good Afternoon!";
    }
}

結果將是:

下午好!

但是,我相信這將是一個大問題。 默認接口的全部原因是允許庫開發人員在不破壞實現者的情況下發展 api。

可以理解的是,它們不允許通過擴展在沒有繼承結構的情況下編譯方法,因為庫開發人員可能會劫持行為。

然而,這有可能自我挫敗。 如果一個類實現了兩個從層次結構視圖中不相關的接口,但都定義了相同的默認方法簽名,那么擴展這兩個接口的類將不會編譯。 (如上所示)

可以想象,兩個不同的庫開發人員可以決定在不同時間使用公共簽名添加默認方法; 事實上,這很可能會發生在實現類似概念的庫中,例如數學庫。 如果您碰巧在同一個類中實現了兩個接口,那么您將在更新時崩潰。

我相信規則是實現重復默認方法的類“必須”覆蓋實現..以下編譯並運行良好......

public class DupeDefaultInterfaceMethods {

interface FirstAbility {
    public default boolean doSomething() {
        return true;
    }
}

interface SecondAbility {
    public default boolean doSomething() {
        return true;
    }
}

class Dupe implements FirstAbility, SecondAbility {
    @Override
    public boolean doSomething() {
        return false;
    }
}

public static void main(String[] args) {
    DupeDefaultInterfaceMethods ddif = new DupeDefaultInterfaceMethods();
    Dupe dupe = ddif.new Dupe();
    System.out.println(dupe.doSomething());

    }
}

> false

Java 8 中的默認方法可以看作是一種多重繼承的形式(除了屬性不能被繼承)。

默認方法背后的主要動機是,如果在某個時候我們需要向現有接口添加一個方法,我們可以在不更改現有實現類的情況下添加一個方法。 這樣,接口仍然兼容舊版本。 這是一個很酷的功能。 但是,我們應該記住使用默認方法的動機,並應該保持接口和實現的分離。

interface First{ 
    // default method 
    default void show(){ 
         System.out.println("Default method implementation of First interface."); 
}  } 

interface Second{ 
   // Default method 
   default void show(){ 
        System.out.println("Default method implementation of Second interface."); 
}  } 

// Implementation class code 
public class Example implements First, Second{ 
    // Overriding default show method 
    public void show(){
       First.super.show();
       Second.super.show();
} 
    public static void main(String args[]){ 
       Example e = new Example(); 
       e.show(); 
}  }

這是簡單的方法:

public interface Circle{
 default String shape() {
    return "Circle drawn...";
 }
}

public interface Rectangle{
default String shape() {
    return "Rectangle drawn...";
}
}

public class Main implements Circle, Rectangle{       
@Override
public String shape() {
    return Circle.super.shape();// called using InterfaceName.super.methodName
}
}

Output:

畫的圓...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM