📜  Java多重继承

📅  最后修改于: 2020-03-22 14:19:39             🧑  作者: Mango

多重继承是面向对象概念的一项功能,其中一个类可以继承多个父类的属性。当在超类和子类中都存在具有相同签名的方法时,就会出现问题。在调用该方法时,编译器无法确定要调用的类方法,甚至无法在调用哪个类方法获得优先级时确定。

为什么Java不支持多重继承?

考虑下面的Java代码。它显示错误。

// Parent1类
class Parent1
{
    void fun()
    {
        System.out.println("Parent1");
    }
}
// Parent2类
class Parent2
{
    void fun()
    {
        System.out.println("Parent2");
    }
}
// 报错
class Test extends Parent1, Parent2
{
   public static void main(String args[])
   {
       Test t = new Test();
       t.fun();
   }
}

输出:

Compiler Error

从代码中,我们看到,使用Test对象调用方法fun()会导致编译器蒙圈,不知调用Parent1的fun()还是Parent2的fun()方法。
1.钻石问题:

          GrandParent
           /     \
          /       \
      Parent1      Parent2
          \       /
           \     /
             Test
// 祖父类
class GrandParent
{
    void fun()
    {
        System.out.println("祖父");
    }
}
// 父类1
class Parent1 extends GrandParent
{
    void fun()
    {
        System.out.println("Parent1");
    }
}
// 父类2
class Parent2 extends GrandParent
{
    void fun()
    {
        System.out.println("Parent2");
    }
}
// 报错
class Test extends Parent1, Parent2
{
   public static void main(String args[])
   {
       Test t = new Test();
       t.fun();
   }
}

从代码中,我们看到:在使用Test对象调用fun()方法时,会引起诸如调用Parent1的fun()或Child的fun()方法之类的困惑。
因此,为了避免此类麻烦,Java不支持类的多重继承。

2.简单性 :Java类不支持多重继承,因此处理因多重继承而导致的复杂性非常复杂。它在各种操作(例如强制转换,构造函数链接等)中产生了问题,并且最重要的原因是,在实际上我们需要多重继承的场景很少,因此最好省略它以使事情简单明了。

对于默认方法和接口,上述问题如何处理?

Java 8支持默认方法,其中接口可以提供方法的默认实现。一个类可以实现两个或多个接口。如果两个已实现的接口都包含具有相同方法签名的默认方法,则实现类应显式指定要使用的默认方法,或者应重写默认方法。

// Java展示默认方法
interface PI1
{
    // 默认方法
    default void show()
    {
        System.out.println("默认 PI1");
    }
}
interface PI2
{
    // 默认方法
    default void show()
    {
        System.out.println("默认 PI2");
    }
}

class TestClass implements PI1, PI2
{
    // 重写
    public void show()
    {

        PI1.super.show();

        PI2.super.show();
    }
    public static void main(String args[])
    {
        TestClass d = new TestClass();
        d.show();
    }
}

输出:

默认 PI1
默认 PI2

如果从“ TestClass”中删除默认方法的实现,则会出现编译器错误。

如果通过接口有钻石问题,那么如果没有中间接口提供根接口的实现就没有问题。如果他们提供实现,则可以使用super关键字按上述方式访问实现。

// Java展示默认方法
interface GPI
{
    // 默认方法
    default void show()
    {
        System.out.println("默认 GPI");
    }
}
interface PI1 extends GPI { }
interface PI2 extends GPI { }

class TestClass implements PI1, PI2
{
    public static void main(String args[])
    {
        TestClass d = new TestClass();
        d.show();
    }
}

输出:

默认 GPI