2014年8月11日

Java 8 Default Methods

Java 8為介面(Interface)引進了一個新的特性,名為Default Method,講白一點其實就是可以在介面內寫一些已經實作的方法。也就是說,在Java 8介面不再只是開規格給類別實作而已,他現在還可以提供一些已經實作的方法給人使用。

如何宣告與使用?

Default Method的宣告方法很簡單,只要加上default關鍵字即可,需要注意的是,在介面內的方法必須宣告為public的。可以參考以下程式:

public interface MyInterfaceI {
    default public void testDefaultMethod(int i) {
        System.out.println("default method test2()");
        if(i > 3) {
            System.out.println(">3");
        } else {
            System.out.println("<=3");
        }
    }
}

要使用該Default Method時,只要透過實現該介面的類別,呼叫該Default Method即可,如下:

class MyInterfaceImpl implements MyInterfaceI {
}

public class MainClass {
    public static void main(String[] args) {
        MyInterfaceImpl impl = new MyInterfaceImpl();
        impl.testDefaultMethod(2); // output: <=3
    }
}

需要注意?

  • 繼承介面時,若父介面有Default Method,則子介面會繼承他。如底下的範例:

      public class InterfaceImpl implements InterfaceSon{
          public static void main(String[] args) {
              InterfaceSon son = new InterfaceImpl();
              son.test(); // output => InterfaceParent
          }
      }
    
      interface InterfaceParent {
          public default void test() {
              System.out.println("InterfaceParent");
          }
      }
    
      interface InterfaceSon extends InterfaceParent{
      }
    
  • Default Method是可以被覆寫(override)的,因此繼承之後你可以將之覆寫掉。如底下的範例,將繼承的介面Default Method覆寫掉,則程式在執行時就會跑覆寫的那個版本:

      public class InterfaceImpl implements InterfaceSon{
          public static void main(String[] args) {
              InterfaceSon son = new InterfaceImpl();
              son.test(); // output => InterfaceSon
          }
      }
    
      interface InterfaceParent {
          public default void test() {
              System.out.println("InterfaceParent");
          }
      }
    
      interface InterfaceSon extends InterfaceParent{
          public default void test() {
              System.out.println("InterfaceSon");
          }
      }
    
  • 繼承之後,若不想要使用原本父類別的Default Method,則可宣告成抽象方法,讓實作類別實作該方法。可以參考底下範例:

      public class InterfaceImpl implements InterfaceSon{
          public static void main(String[] args) {
              InterfaceSon son = new InterfaceImpl();
              son.test(); // output => InterfaceImpl
          }
    
          @Override
          public void test() {
              System.out.println("InterfaceImpl");
          }
      }
    
      interface InterfaceParent {
          public default void test() {
              System.out.println("InterfaceParent");
          }
      }
    
      interface InterfaceSon extends InterfaceParent{
          public void test();
      }
    
  • 如果類別要實作的介面,剛好有兩個相同名稱,相同輸入參數的Default Method,則編譯器會出錯。可以參考底下程式:

      public class InterfaceImpl implements Interface1, Interface2 {
          // 編譯器會報以下錯誤
          // Duplicate default methods named test with the 
          // parameters () and () are inherited from the types 
          // Interface2 and Interface1
      }
    
      interface Interface1 {
          public default void test() {
              System.out.println("Interface1");
          }
      }
    
      interface Interface2 {
          public default void test() {
              System.out.println("Interface2");
          }
      }
    
  • 上面情況發生時,可以用覆寫來把Default Method蓋掉,在覆寫時還可以用super關鍵字來指定要用哪個實作的Default Method,可以參考底下程式:

      public class InterfaceImpl implements Interface1, Interface2{
          public void test() {
              Interface1.super.test(); // output => Interface1
          }
      }
    
      interface Interface1 {
          public default void test() {
              System.out.println("Interface1");
          }
      }
    
      interface Interface2 {
          public default void test() {
              System.out.println("Interface2");
          }
      }
    
  • Default Method在使用時是沒有狀態的,所謂的狀態指的是在一般類別與抽象(abstract)類別裡,能在類別的欄位(field)存放資料,如存放布林值、整數、字串等等的資料,來代表此類別的狀態,而Default Method是存在於介面內的,介面是不允許存放資料欄位的,因此它唯一能操作的資料,只有透過參數傳進來的資料而已。

Static Methods

此外除了Default Method,現在在Java 8內,你也可以寫Static Method了,他的宣告方法就如同在一般類別內宣告static method一樣,如下:

public interface MyInterfaceI {
    public static void invokeStaticMethod() {
        System.out.println("It is static method!");
    }
}

使用的話如下:

public class MainClass {
    public static void main(String[] args) {
        MyInterfaceI.invokeStaticMethod(); // output: It is static method!
    }
}

Interface Default Methods in Java 8

The Java Tutorials - Default Methods