阅读 60

Java默认接口方法引发的多继承问题

Java8中的抽象类和抽象接口区别

首先,一个类只能继承一个抽象类,但是一个类可以实现多个接口

其次,一个抽象类可以通过实例变量(字段)保存一个通用状态,而接ロ是不能有实例变量的

熟悉Java或者看过Java面试题的都知道,Java不支持多继承,原因是:

  • 安全性的考虑,如果子类继承的多个父类里面有相同的方法或者属性,子类将不知道具体要继承哪个。
  • Java提供了接口和内部类以达到实现多继承功能,弥补单继承的缺陷。

所以在实际开发中可以通过多个接口来灵活实现,但Java8中支持接口编写默认方法,变相等于可以继承多个类。

interface A{
    default void a(){
        System.out.println("a");
    }
}
abstract class B{
    public void b(){
        System.out.println("b");
    }
}
class C extends B implements A{
    public void c(){
        System.out.println("c");
    }
}
复制代码

Java8的这种改进源于接口升级迭代存在的问题,一旦在接口中新加入方法,异味着所有实现该接口的类都要实现该方法,例如List接口增加新的方法, ArrayList ,List, LinkedList, Vector以及所有相关的类都要发生变化,这简直就是灾难,对整个项目会产生非常大的影响,所以我理解Java开发者为了加入新的功能而又不影响现有代码的运行,容许接口中来编写默认方法,默认方法在Java8的API中已经大量地使用了。如大量使用的co11ection接口的 stream方法就是默认方法。list接口的sort方法也是默认方法。很多函数式接口,比如 Predicate、 Functionl以及 Comparator也引人了新的默认方法,比如 Predicate.and或者 Function. andthen,list新加入的sort排序。

default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }
复制代码

由于接口现在可以提供带实现的方法,这意味着Java已经在某种程度上实现了多继承,如果实现类也实现了同样的方法默认方法会被覆盖吗,Java8中已经定义了一些规则和机制来处理这些问题。

如果一个类使用相同的函数签名从多个地方(比如另一个类或接口)继承了方法,通过三条规则可以进行判断。

(1)类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。

(2)如果无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。

(3)最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法。

文章分类
后端
文章标签