預設方法

在 Java 8 中引入,預設方法是一種在介面內指定實現的方法。這可以用於通過提供介面的部分實現並限制子類層次結構來避免典型的 BaseAbstract 類。

觀察者模式實現

例如,可以將 Observer-Listener 模式直接實現到介面中,從而為實現類提供更大的靈活性。

interface Observer {
    void onAction(String a);
}

interface Observable{
    public abstract List<Observer> getObservers();

    public default void addObserver(Observer o){
        getObservers().add(o);
    }

    public default void notify(String something ){
        for( Observer l : getObservers() ){
            l.onAction(something);
        }
    }
}

現在,只需通過實現 Observable 介面就可以使任何類成為 Observable,同時可以自由地成為不同類層次結構的一部分。

abstract class Worker{
    public abstract void work();
}

public class MyWorker extends Worker implements Observable {

    private List<Observer> myObservers = new ArrayList<Observer>();
    
    @Override
    public List<Observer> getObservers() {
        return myObservers;
    }

    @Override
    public void work(){
        notify("Started work");

        // Code goes here...

        notify("Completed work");
    }
    
    public static void main(String[] args) {    
        MyWorker w = new MyWorker();
       
        w.addListener(new Observer() {
            @Override
            public void onAction(String a) {
                System.out.println(a + " (" + new Date() + ")");
            }
        });
        
        w.work();
    }
}

鑽石問題

Java 8 中的編譯器知道當類實現包含具有相同簽名的方法的介面時引起的菱形問題

為了解決這個問題,實現類必須覆蓋共享方法並提供自己的實現。

interface InterfaceA {
    public default String getName(){
        return "a";
    }
}

interface InterfaceB {
    public default String getName(){
        return "b";
    }
}

public class ImpClass implements InterfaceA, InterfaceB {

    @Override
    public String getName() {    
        //Must provide its own implementation
        return InterfaceA.super.getName() + InterfaceB.super.getName();
    }
    
    public static void main(String[] args) {    
        ImpClass c = new ImpClass();
        
        System.out.println( c.getName() );                   // Prints "ab"
        System.out.println( ((InterfaceA)c).getName() );     // Prints "ab"
        System.out.println( ((InterfaceB)c).getName() );     // Prints "ab"
    }
}

仍然存在具有相同名稱和具有不同返回型別的引數的方法的問題,這些方法將無法編譯。

使用預設方法解決相容性問題

如果將方法新增到現有系統中的介面(其中介面由多個類使用),則預設方法實現非常方便。

為避免分解整個系統,可以在向介面新增方法時提供預設方法實現。這樣,系統仍然可以編譯,實際的實現可以一步一步完成。

有關更多資訊,請參閱“ 預設方法” 主題。