有时我写了几篇有关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中的多重继承与组合vs继承相关推荐

  1. java可以多重继承吗_Java中的多重继承与组合vs继承

    java可以多重继承吗 有时我写了几篇有关Java继承,接口和组成的文章. 在这篇文章中,我们将研究多重继承,然后了解组成优于继承的好处. Java中的多重继承 多重继承是创建具有多个超类的单个类的能 ...

  2. 多重继承java_Java中的多重继承与组合vs继承

    多重继承java 有时我写了几篇有关Java 继承 , 接口和组成的文章. 在这篇文章中,我们将研究多重继承,然后了解组成优于继承的好处. Java中的多重继承 多重继承是创建具有多个超类的单个类的能 ...

  3. Java中静态变量与静态方法的继承

    看下面的代码: public class Demo {public static void main(String[] args) {// 子类SonB继承父类Father,子类可以获取父类的所有属性 ...

  4. Java中的多重继承问题

    继承是面向对象编程 (OOP) 语言(如Java)的主要功能之一.它是一种以增强软件设计中类重用能力的方式组织类的基本技术.多重继承是众多继承类型之一,是继承机制的重要原则.但是,它因在类之间建立模棱 ...

  5. 【JAVA系列】Java中的包、类的继承、多态、抽象类与接口

    文章目录 前言 一.包及访问权限 1.什么是包? 2.如何导入包? 3.JDK中常见的包 4.包的访问控制权限 二.继承 1.继承的基本概念 2.继承时方法调用顺序 3.super和this关键字 4 ...

  6. Java中面向对象的三大特征之一——继承

    继承 1.继承是类和类之间的一种关系java中的类和类之间的关系有很多中,继承只是其中一种,其他的还有依赖.组合.聚合等2.继承关系的俩个类,一个是子类,一个是父类子类也可以称为派生类,父类也可以称为 ...

  7. java中允许多重继承吗,java允许接口的多重继承吗

    java类是单继承的.classB Extends classA java接口可以多继承.Interface3 Extends Interface0, Interface1, interface-- ...

  8. Java中的聚合与组合

    一.聚合与组合 继承是面向对象编程三大特性之一,通过继承,子类可以继承父类非private的属性和方法,大大提高代码复用性和开发效率. 但继承也有众多缺点, 比如使得子类与父类过度耦合,当父类发生调整 ...

  9. java中this,super,extends,implements相关继承概念讲解

    在java中有关==继承==这个词有许多关键字:super,this,extends,implements      对于初学者来说着实比较晕,网上说的也是云里雾里.现在个人算是有些眉目了,来一次总结 ...

最新文章

  1. 德国最受欢迎的程序员技能排行
  2. Java面试查漏补缺
  3. AllegroPCB PDN电源分配系统分析
  4. matlab心电图诊断系统,ECG-diag MATLAB心电图自动诊断程序 联合开发网 - pudn.com
  5. Spring Boot之注册servlet三大组件
  6. .net快速入门方法,转csdn
  7. linux,apache,php,mysql常用的查看版本信息的方法
  8. .NET团队送给.NET开发人员的云原生学习资源
  9. linux 启动rsyslog服务_linux rsyslog服务部署
  10. (23)HTTP 状态消息
  11. .Net程序员学用Oracle系列(16):访问数据库(ODP.NET)
  12. spark学习-28-Spark数据倾斜问题
  13. (转)密码学研究与区块链实践应该打破隔空喊话
  14. 【心电信号】基于matlab小波变换心电信号去噪【含Matlab源码 956期】
  15. 一些很有用的JS特效
  16. 大专计算机课教案,计算机课教案
  17. 吴伯凡-认知方法论-我的休息
  18. HTML5 学习笔记(一)——HTML5概要与新增标签
  19. matlab 对数回归,matlab的对数回归
  20. 东莞比较好的java培训学校,先收藏了

热门文章

  1. mininet编程实现交换机规则的插入、删除与修改。_可编程网卡芯片在滴滴云网络的应用实践...
  2. 赞扬别人团建评论_赞扬精心设计:基于属性的测试如何帮助我成为更好的开发人员...
  3. switch字符串jdk_JDK 12 Early Access Build 12中的原始字符串文字支持
  4. 用jackson转json_用Jackson编写大JSON文件
  5. tomee_OpenLiberty:注入错误,适用于TomEE和Wildfly
  6. jboss项目导入idea_JBoss BPM Suite快速指南–将外部数据模型导入BPM项目
  7. gtest 测试部分_全部关于测试–第2部分
  8. Docker化Spring Boot应用程序
  9. 针对JDK 14提议的另外六个JEP
  10. weblogic工具_WebLogic Classloader分析工具