默认方法

在 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"
    }
}

仍然存在具有相同名称和具有不同返回类型的参数的方法的问题,这些方法将无法编译。

使用默认方法解决兼容性问题

如果将方法添加到现有系统中的接口(其中接口由多个类使用),则默认方法实现非常方便。

为避免分解整个系统,可以在向接口添加方法时提供默认方法实现。这样,系统仍然可以编译,实际的实现可以一步一步完成。

有关更多信息,请参阅“ 默认方法” 主题。