接口默认方法冲突

如果先在一个接口中将一个方法定义为默认方法,然后又在超类或另一个接口中定义了同样的方法,就会产生一个二义性错误.对于解决这个问题,java提供了相对简单的规则.
1)超类优先.如果超类提供了一个具体方法,同名并且有相同参数的默认方法会被忽略
2)接口冲突.如果一个接口提供了一个默认方法,另一个接口提供了一个同名而且参数类型相同的方法,必须覆盖这个方法来解决冲突

首先我们先看第二个规则:

    1
    2
    3
    4
    5

//: 测试接口默认方法的冲突

interface Named {
    default String getName() {
        return getClass().getName() + "_" + hashCode() + "    Named";
}

interface Base {
    default String getName() {
        return getClass().getName() + "_" + hashCode() + "   Base";
    }
}

public class Test implements Base, Named {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.getName());
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

如上述代码所见,Test类同时实现了两个有同名且参数相同的默认方法的接口.编译后产生如下错误:
这里写图片描述
类会继承Base和Named接口提供的两个不一致的getName方法.并不是从中选择一个,java编译器会报告一个错误,让程序员来解决这个二义性.只需要在Test类中提供一个getName方法.在这个方法中,可以选择两个冲突方法中的一个,如下所示:

//: 测试接口默认方法的冲突

interface Named {
    default String getName() {
        return getClass().getName() + "_" + hashCode() + "   Named";
    }
}

interface Base {
    default String getName() {
        return getClass().getName() + "_" + hashCode() + "   Base";
    }
}

public class Test implements Base, Named {
    //覆盖getName方法
    public String getName() {
        return Named.super.getName();
    }

    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.getName());
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26

这里写图片描述
这样我们就能解决这个问题.
现在假设Named接口没有为getName提供默认实现:
Test类会从Base接口继承默认方法么?

//: 测试接口默认方法的冲突

interface Named {
    String getName();
}

interface Base {
    default String getName() {
        return getClass().getName() + "_" + hashCode() + "   Base";
    }
}

public class Test implements Base, Named {
    public static void main(String[] args) {
        Test t = new Test();
        System.out.println(t.getName());
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

这里写图片描述
我们可以看到编译器依然还是报错.
java设计者强调一致性.两个接口如何冲突并不重要.如果至少一个接口提供了一个实现,编译器就会报告一个错误,而程序员就要解决这个个二义性.
当然,如果两个接口都没有为共享方法提供默认实现,这里就不存在冲突.实现类可以有两个选择:实现这个方法,或者干脆不实现.如果不实现,那么这个实现类本身就是抽象的.

现在来考虑另一种情况,一个类继承了一个超类,同时实现了一个接口,并从超类和接口继承了相同的方法.

//: 超类与接口方法冲突

interface Named {
    default String getName() {
        return getClass().getName() + "_" + hashCode() + "    Named";
    }
}

class Base {
    public String getName() {
        return getClass().getName() + "_" + hashCode() + "   Base";
    }
}

public class Test2 extends Base implements Named {
    public static void main(String[] args) {
        Test2 t = new Test2();
        System.out.println(t.getName());
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

output:
这里写图片描述
在这种情况下,只会考虑超类方法,接口的所有默认方法都会被忽略.这正是”类优先”原则.

参考资料:corejava
---------------------
作者:shallowinggg
来源:CSDN
原文:https://blog.csdn.net/shallowinggg/article/details/78039372
版权声明:本文为博主原创文章,转载请附上博文链接!

posted @ 2019-05-14 19:15  天涯海角路  阅读(292)  评论(0)    收藏  举报