Java8中的“菱形继承”问题_潇兮水寒的博客

CSDN博客_java菱形继承 · · 2249 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

什么是菱形继承

一张图说明。在C++中允许多继承,D类继承自B、C,而B、C有同一个父类A。那么这个时候调用say方法是否成功?答案是不能,编译器并不能判断这个say来自哪个父类。
在这里插入图片描述

#include<iostream>
using namespace std;

class A{
public:
    void say(){
        cout<<"Say Hello"<<endl;
    }
};

class B:public A{

};

class C:public A{

};

class D:public B,public C{


};

int main(){
    D d;
    d.say(); //出错,返回request for member 'say' is ambiguous
    d.B::say();
    d.C::say();  
    return 0;
}

C++的解决办法有两个:一是指定域,使用::,二是虚继承。

那么,为什么在Java不支持多继承为什么也会出现“菱形继承”呢,这主要是归功于JDK8中出现一个新关键字default,总所周知,Java支持多继承,那出现了这个default关键字让interface成员方法也能有实现,那么如果出现这种“多实现”问题,会不会也出现“菱形继承问题”?

Java代码

场景一

Human是超级接口,里面有一个say方法,类F1、类F2继承Human,但并没有重写这个default方法


/**
 * 菱形继承问题
 */
public class RhombusExtendTest {
    private static interface Human{
        default void say(){
            System.out.println("Human Hello !");
        }
    }
    private static interface F1 extends Human{
        default void f1Func(){
            System.out.println("F1 f1Func !");
        }
    }
    private static interface F2 extends Human{
        default void f2Func(){
            System.out.println("F1 f1Func !");
        }
    }
    private static class Son implements F1,F2{

    }

    public static void main(String[] args) {
        Son son = new Son();
        son.say();
        son.f1Func();
        son.f2Func();
    }
}

Human Hello !
F1 f1Func !
F1 f1Func !
Process finished with exit code 0

这种情况下,菱形继承没有复现,那么类F1、类F2、类Son都可以访问Human的Say()方法。

场景二

Human是超级接口,里面有一个say方法,类F1、类F2继承Human,并且重写了这个default方法

/**
 * 菱形继承问题
 */
public class RhombusExtendTest {
    private static interface Human{
        default void say(){
            System.out.println("Human Hello !");
        }
    }
    private static interface F1 extends Human{
        @Override
        default void say(){
            System.out.println("F1 test !");
        }
        default void f1Func(){
            System.out.println("F1 f1Func !");
        }
    }
    private static interface F2 extends Human{
        @Override
        default void say(){
            System.out.println("F2 test !");
        }
        default void f2Func(){
            System.out.println("F1 f1Func !");
        }
    }
    private static class Son implements F1,F2{

    }

    public static void main(String[] args) {
        Son son = new Son();
        son.say();//出错!这里编译器不知道应该用类F1还是类F2的say方法
        son.f1Func();
        son.f2Func();
    }
}


编译报错!
RhombusExtendTest.F1 和 RhombusExtendTest.F2 中继承了test() 的不相关默认值

这里便出现了Java版的“菱形继承”的问题。当然,如果你使用了idea这种编译器,它会推荐你去实现这个方法。

简单结论

目前Java8解决这种冲突一般遵循三个原则

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

解决办法

那如果说,在Son对象中,就是想调用F1或者F2类的say方法呢?
其实,Java也提供了类似C++中的“域”的概念。

首先这个say方法肯定不满足前两点,编译器不知道你会使用F1还是F2中的say方法,那么,这里就必须要显示覆盖
公式:

类名.super.默认方法

代码如下

/**
 * 菱形继承问题
 */
public class RhombusExtendTest {
    private static interface Human{
        default void say(){
            System.out.println("Human Hello !");
        }
    }
    private static interface F1 extends Human{
        @Override
        default void say(){

            System.out.println("F1 test !");
        }
        default void f1Func(){
            System.out.println("F1 f1Func !");
        }
    }
    private static interface F2 extends Human{
        @Override
        default void say(){
            System.out.println("F2 test !");
        }
        default void f2Func(){
            System.out.println("F2 f1Func !");
        }
    }
    private static class Son implements F1,F2{
        //这里还是不满足前面三点,需要覆盖say方法
        @Override public void say() {
            //调用F1中的say方法
            F1.super.say();
        }
    }

    public static void main(String[] args) {
        Son son = new Son();
        son.say();
        son.f1Func();
        son.f2Func();
    }
}

结果如下:正确调用了F1中的say方法
F1 test !
F1 f1Func !
F1 f1Func !

参考:
《Java8实战》

本文来自:CSDN博客_java菱形继承

感谢作者:CSDN博客_java菱形继承

查看原文:Java8中的“菱形继承”问题_潇兮水寒的博客

2249 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传