java可以多重继承吗

有时我写了几篇有关Java继承接口组成的文章。 在这篇文章中,我们将研究多重继承,然后了解组成优于继承的好处。

Java中的多重继承

多重继承是创建具有多个超类的单个类的能力。 与其他一些流行的面向对象的编程语言(例如C ++)不同, java不提供对类中多重继承的支持。 Java不支持类中的多重继承,因为它可能导致钻石问题,而不是提供一些复杂的方法来解决它,而是有更好的方法来实现与多重继承相同的结果。

钻石问题

为了轻松理解钻石问题,我们假定Java中支持多重继承。 在这种情况下,我们可以像下面的图像那样有一个类层次结构。

假设SuperClass是一个抽象类,声明了一些方法,而ClassA,ClassB是具体类。

超类.java

package com.journaldev.inheritance;public abstract class SuperClass {public abstract void doSomething();
}

ClassA.java

package com.journaldev.inheritance;public class ClassA extends SuperClass{@Overridepublic void doSomething(){System.out.println("doSomething implementation of A");}//ClassA own methodpublic void methodA(){}
}

ClassB.java

package com.journaldev.inheritance;public class ClassB extends SuperClass{@Overridepublic void doSomething(){System.out.println("doSomething implementation of B");}//ClassB specific methodpublic void methodB(){}
}

现在,让我们说ClassC的实现如下所示,它扩展了ClassA和ClassB。

ClassC.java

package com.journaldev.inheritance;public class ClassC extends ClassA, ClassB{public void test(){//calling super class methoddoSomething();}}

注意, test()方法正在调用超类doSomething()方法,这导致歧义,因为编译器不知道要执行哪个超类方法,并且由于菱形类图,它被称为Diamond Problem,这是Java不支持类中的多重继承的主要原因。

请注意,具有多个类继承的上述问题也可能只出现在三个类中,它们全部具有至少一个通用方法。

接口中的多重继承

您可能已经注意到,我一直在说类不支持多重继承,但是接口支持多重继承,并且单个接口可以扩展多个接口,下面是一个简单的示例。

接口A.java

package com.journaldev.inheritance;public interface InterfaceA {public void doSomething();
}

接口B.java

package com.journaldev.inheritance;public interface InterfaceB {public void doSomething();
}

注意,两个接口都声明了相同的方法,现在我们可以拥有一个扩展这两个接口的接口,如下所示。

接口C.java

package com.journaldev.inheritance;public interface InterfaceC extends InterfaceA, InterfaceB {//same method is declared in InterfaceA and InterfaceB bothpublic void doSomething();}

这样做非常好,因为接口仅声明方法,并且实际实现将由实现接口的具体类完成,因此在接口的多重继承中不存在任何歧义的可能性。

这就是为什么Java类可以实现多重继承的原因,例如下面的示例。

接口Impl.java

package com.journaldev.inheritance;public class InterfacesImpl implements InterfaceA, InterfaceB, InterfaceC {@Overridepublic void doSomething() {System.out.println("doSomething implementation of concrete class");}public static void main(String[] args) {InterfaceA objA = new InterfacesImpl();InterfaceB objB = new InterfacesImpl();InterfaceC objC = new InterfacesImpl();//all the method calls below are going to same concrete implementationobjA.doSomething();objB.doSomething();objC.doSomething();}}

您是否注意到,每当我覆盖任何超类方法或实现任何接口方法时,我都使用@Override注释,它是三个内置的Java注释之一,并且 在覆盖任何方法时都应 始终使用覆盖注释。

救援人员组成

因此,如果我们想在ClassC使用ClassA函数methodA()ClassB函数methodB() ,该解决方案在于使用composition ,这是ClassC的重构版本,该版本使用了composition来利用这两种类方法以及doSomething ()方法来自其中一个对象。

ClassC.java

package com.journaldev.inheritance;public class ClassC{ClassA objA = new ClassA();ClassB objB = new ClassB();public void test(){objA.doSomething();}public void methodA(){objA.methodA();}public void methodB(){objB.methodB();}
}

组合与继承

Java编程的最佳实践之一是“通过接口支持组合”,我们将研究一些偏爱这种方法的方面。

  1. 假设我们有一个超类和子类,如下所示:

    ClassC.java

    package com.journaldev.inheritance;public class ClassC{public void methodC(){}
    }

    ClassD.java

    package com.journaldev.inheritance;public class ClassD extends ClassC{public int test(){return 0;}
    }

    上面的代码可以编译并正常工作,但是如果ClassC实现更改如下:

    ClassC.java

    package com.journaldev.inheritance;public class ClassC{public void methodC(){}public void test(){}
    }

    请注意,子类中已经存在test()方法,但返回类型有所不同,现在ClassD将无法编译,并且如果您使用的是任何IDE,它将建议您更改超类或子类中的返回类型。

    现在想象一下这样的情况:我们具有多个级别的类继承,并且超类不受我们控制,我们别无选择,只能更改我们的子类方法签名或名称以消除编译错误,我们还必须在所有方面进行更改子类方法被调用的地方,因此继承使我们的代码易碎。

    组合永远不会发生上述问题,这使其比继承更有利。

  2. 继承的另一个问题是,我们将所有超类方法公开给客户端,并且如果我们的超类设计不当且存在安全漏洞,那么即使我们在实现类时全神贯注,我们也会受到不良实现的影响。超类。组合可以帮助我们提供对超类方法的受控访问,而继承不提供对超类方法的任何控制,这也是组合优于继承的主要优势之一。
  3. 组合的另一个好处是它提供了方法调用的灵活性。 我们上ClassC实现不是最佳的,它提供了与将要调用的方法的编译时绑定,只需进行最小的更改,我们就可以使方法调用变得灵活并使其动态。

    ClassC.java

    package com.journaldev.inheritance;public class ClassC{SuperClass obj = null;public ClassC(SuperClass o){this.obj = o;}public void test(){obj.doSomething();}public static void main(String args[]){ClassC obj1 = new ClassC(new ClassA());ClassC obj2 = new ClassC(new ClassB());obj1.test();obj2.test();}
    }

    上面程序的输出是:

    doSomething implementation of A
    doSomething implementation of B

    方法调用的这种灵活性在继承中不可用,并且提倡了最佳做法,即在继承方面偏向于组合。

  4. 单元测试很容易组合,因为我们知道超类中正在使用的所有方法,并且可以对其进行模拟,而在继承中,我们很大程度上依赖于超类,并且不知道将使用所有超类方法,因此我们需要要测试超类的所有方法,这是一项额外的工作,由于继承,我们不需要这样做。

理想情况下,仅当在所有情况下父类和子类的“ is-a ”关系均成立时才应使用继承,否则我们应该继续进行组合。

参考: Developer Recipes博客上的JCG合作伙伴Pankaj Kumar的Java多重继承与Composition vs Inheritance 。

翻译自: https://www.javacodegeeks.com/2013/08/multiple-inheritance-in-java-and-composition-vs-inheritance.html

java可以多重继承吗

java可以多重继承吗_Java中的多重继承与组合vs继承相关推荐

  1. java是什么意思_java中是什么意思?

    慕田峪7331174 Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言.Java技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算机.移动 ...

  2. java中有没有栈_Java中堆和栈有什么区别

    stack 和 heep 都是内存的一部分stack 空间小,速度比较快, 用来放对象的引用heep 大,一般所有创建的对象都放在这里.栈(stack):是一个先进后出的数据结构,通常用于保存方法(函 ...

  3. java 基本类型 引用_java中 引用类型 和 基本类型 有何区别?

    栈与堆都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new.newa ...

  4. java构造器详解_Java中关于构造器的使用详解

    这篇文章主要介绍了Java构造器使用方法及注意事项的相关资料,这里举例说明如何使用构造器及需要注意的地方,需要的朋友可以参考下 Java构造器使用方法及注意事项 超类的构造器在子类的构造器运行之前运行 ...

  5. java读取文件 路径_Java中的获取文件的物理绝对路径,和读取文件

    获取文件的绝对路径,读取该文件 一.文件目录打印图 下面的文件目录图,是项目中文件的位置信息:下面的例子是按照这个图来演示的. . |-- java | |-- ibard | | |-- demo1 ...

  6. java多线程 线程安全_Java中的线程安全

    java多线程 线程安全 Thread Safety in Java is a very important topic. Java provides multi-threaded environme ...

  7. java 异常处理发生异常_Java中的异常处理

    java 异常处理发生异常 Exception Handling in Java is a very interesting topic. Exception is an error event th ...

  8. java string 对象地址_Java中String对象的存储位置(学习笔记)

    packagetest.string.equal;public classMain {/*** 创建了三个对象,"helloworld对象创建在常量池中",每次new String ...

  9. java 定义整数数组_JAVA中数组的正确定义方法是什么?

    数组是有序数据的集合,数组中的每个元素具有相同的数组名和下标来唯一地确定数组中的元素. §5.1一维数组 一.一维数组的定义 type arrayName[]; 其中类型(type)可以为Java中任 ...

最新文章

  1. Redis 笔记(13)— scan 和 keys 寻找特定前缀key 字段(命令格式、使用示例、定位大key)
  2. 遗传算法与直接搜索工具箱学习笔记 -----从直接搜索算法开始
  3. 计算一列中某个值的个数
  4. Asp.net(C#)给图片加上水印效果
  5. chmod是linux命令吗,Linux chmod命令怎么用
  6. bootstrap学习笔记(2)表单设计
  7. yum挂在iso文件yum源配置
  8. 实现一个HTTP服务器的Demo
  9. Sakai Demo搭建及遇到的问题汇总
  10. java面试题及答案2020 (二十五)
  11. web前端项目 - cypress自动化测试运行构建
  12. Drupal 建站
  13. Building QNX guests
  14. java查询序列_基于JAVA的苹果序列号查询api调用代码实例
  15. Mac搭建Flink集群
  16. Linux 运维基础
  17. 烂大街的TCP/IP网络模型,你真的懂了?
  18. 【github】Support for password authentication was removed on August 13,2021.
  19. 大学物理复习——静电场中的导体和电介质
  20. ZYNQ芯片AXI 协议和PL和PS接口互联

热门文章

  1. 在Intellij Idea中使用jstl标签库
  2. SpringBoot 的其他使用 及 maven打包
  3. 23种设计模式之外观模式(Facade)
  4. ubuntu 12.04 桌面版关闭图形界面
  5. 安卓开发30:AsyncTask的用法
  6. 华为防火墙USG基本配置
  7. Tomcat6.0的JNDI使用方法(连接池)
  8. linux 安装jdk yum安装 源码包安装
  9. docker 批量删除 镜像或容器 删除所有容器
  10. linux c printf 打印输出null