• Java8中默认实现如何解决冲突?


    前置知识

    Java中的多态应该都不陌生,这一特性是通过继承父类或者实现父接口来展现的。但是父类或者父接口中定义的方法可能不能满足新需求了。那么很容易想到在原始类中添加方法,但是子类或者实现类都需要变动,显然是相当难维护,为了解决这个问题,Java 8允许在接口内声明静态方法,且允许接口中定义默认方法(default关键字)。

    这里所说的重点就是引进了default之后,如果某一个具体类 实现了多个具有相同的签名的默认方法之后,Java8 是如何解决冲突的?

    解决冲突的规则

    1. 类中的方法优先级最高。类和父类中的方法优先于其他类。
    2. 如果无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。
    3. 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,显式地选择使用哪一个默认方法的实现。

    案例

    规则一

        public interface A {
            default void hello() {
                System.out.println("Hello from A");
            }
        }
        
        public class D implements A{
    		void hello() {
                System.out.println("Hello from D");
            }
    	}
        
        public interface B extends A {
            default void hello() {
                System.out.println("Hello from B");
            }
        }
        public class C extends D implements B, A {
            public static void main(String... args) {
                new C().hello();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    由于有继承关系,所以按照规则1先进行查找,C类继承自D,而D含有A接口hello方法的重写,所以这里打印"Hello from D"


    规则2

        public interface A {
            default void hello() {
                System.out.println("Hello from A");
            }
        }
        
        public class D implements A{}
        
        public interface B extends A {
            @Override
            default void hello() {
                System.out.println("Hello from B");
            }
        }
        public class C extends D implements B, A {
            public static void main(String... args) {
                new C().hello();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    由于有继承关系,所以按照规则1先进行查找,C类继承自D,而D没覆盖hello方法,所以只能拥有接口A的hello方法的默认实现,所以C现在拥有了A接口的hello;规则(2)说如果类或者父类没有对应的方法,那么就应该选择提供了最具体实现的接口中的方法。而这里C实现了B,发现B中更加具体(B中hello是对A接口hello的实现),所以程序会再次打印输出“Hello from B”


    规则3

    如下所示,这里没有哪个接口的hello更具体

        public interface A {
            void hello() {
                System.out.println("Hello from A");
            }
        }
        public interface B {
            void hello() {
                System.out.println("Hello from B");
            }
        }
        // 显式消除
        public class C implements B, A {
            void hello(){
                B.super.hello();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    通过在C中显示覆盖hello 指定调用谁的hello方法。

    附录

    菱形继承问题

        public interface A{
            default void hello(){
                System.out.println("Hello from A");
            }
        }
        public interface B extends A { }
        public interface C extends A { }
        public class D implements B, C {
            public static void main(String... args) {
                new D().hello();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    其继承关系如下所示:
    <img src=">

    因为继承关系如菱形,所以被称为菱形问题。

    只有A声明了一个默认方法。由于这个接口是D的父接口,代码会打印输出“Hello from A”

  • 相关阅读:
    k8s 网络持久化存储之StorageClass(如何一步步实现动态持久化存储)
    用新服务器从零开始部署 DolphinDB
    xshell使用vi命令:bash:vim:command not found
    Python中dataclass库
    python自动化测试之selenium环境安装
    【Vue3 知识第七讲】reactive、shallowReactive、toRef、toRefs 等系列方法应用与对比
    记一次MySQL崩溃修复案例,再也不用删库跑路了
    2022 极术通讯-《服务器应用场景性能测试方法 虚拟化》解读
    在RVIZ中进行可视化操作
    C++11alignas 说明符和alignof 运算符和内存对齐问题
  • 原文地址:https://blog.csdn.net/weixin_43626356/article/details/127625853