Java中的多重继承问题

news2024/9/27 21:29:40

继承是面向对象编程 (OOP) 语言(如Java)的主要功能之一。它是一种以增强软件设计中类重用能力的方式组织类的基本技术。多重继承是众多继承类型之一,是继承机制的重要原则。但是,它因在类之间建立模棱两可的关系而臭名昭著。因此,Java设计师放弃了这个想法,尽管不是完全放弃。本文探讨了继承的一些概念,以及 Java 中多重继承的复杂性。

概述

继承创建子类的层次结构,其中子类扩展父类的功能。这样做不仅是为了继承超类的功能,也是为了通过继承的类赋予新的含义。这种功能的扩展通常是通过重写超类的功能、添加新的方法和属性来完成的。在 Java 中,对于可以从超类派生的子类的数量没有实际限制。但是,层次结构必须遵循线性方式。

因此,在创建子类时,我们指定它使用现有类的成员,而不是声明所有新的类成员。现有类称为超类,新类称为子类,其中每个子类都能够在继承层次结构中进一步扩展成为超类。此层次结构如图 1 所示。


图 1:用于说明继承的 UML 图(由 Creately 提供的 UML 图工具提供)

继承的类型

一般而言,各种面向对象的编程语言支持多种类型的继承,例如单级继承、多级继承、多级继承、多路径继承、分层和混合继承。请注意,这些类型差异纯粹是学术性的;OOP 语言在实践中使用其中一种或多种类型。

  • 单级继承:在这里,子类派生自单个超类。
  • 多级继承:这是单级继承的扩展,但每个子类都有能力成为未来子类的超类。每个继承都保持一条线性路径。
  • 多重继承:此处,子类派生自多个基类。Java 不支持这种类型的继承,但C++支持它。
  • 多路径继承:这是多重继承的扩展,其中子类派生自基类和基类的多个子类。很明显,Java也不支持这种类型的继承。
  • 分层继承:在这种类型的继承中,可以从单个超类创建多个派生类,并且可以在树结构中扩展进程。
  • 混合继承:这只不过是多种继承类型的组合。

Java 中的多级单一继承

Java 支持单一继承,其中每个类都只派生自一个直接超类。派生的每个子类都有可能成为未来子类的超类。在单级继承中,子类继承父类的属性。我们还可以从单个父类创建多个子类,该子类可能是另一个父类的子类。因此,多级单继承本质上意味着我们可以将单级类层次结构的概念扩展到多个层次。

一个快速的例子

此示例是图 1 中所示的 UML 图的快速实现。

package com.mano.examples;
public class Company {
   public static void main(String[] args) {
      Staff staff = new Staff();
      staff.pay();
   }
}

package com.mano.examples;
import java.util.ArrayList;
import java.util.List;
public class Staff {
   private List<StaffMember> staffMembers = new ArrayList<>();
   public Staff(){
      staffMembers.add(new ExecutiveEmployee
         ("Mickey","Disney Land","1234","987654321",1236.56));
      staffMembers.add(new Employee
         ("Donald","Disney Land","2233","87459985",5603.48));
      staffMembers.add(new RegularEmployee
         ("Zairo","Disney Land","2244","87452658",12.36));
      staffMembers.add(new Apprentice
         ("Minnie","Disney Land","963258741"));
      ((ExecutiveEmployee)staffMembers.get(0)).bonusReceived(1200);
      ((RegularEmployee)staffMembers.get(2)).updateHours(5);
   }
   public void pay(){
      for(StaffMember m: staffMembers){
         System.out.println(m.toString());
         System.out.println("Earnings: "+ m.earnings());
         System.out.println("------------------------------");
      }
   }
}

package com.mano.examples;
abstract public class StaffMember {
   protected String name;
   protected String address;
   protected String phone;
   public StaffMember(String n, String a, String p){
      name = n;
      address = a;
      phone = p;
   }
   @Override
   public String toString() {
      return "StaffMember{" +
          "name='" + name + ''' +
          ", address='" + address + ''' +
          ", phone='" + phone + ''' +
          '}';
   
   }
   public abstract double earnings();
}

package com.mano.examples;
public class Employee extends StaffMember {
   protected String empId;
   protected double rate;
   public Employee(String n, String a, String p,String id,
         double r){
      super(n,a,p);
      empId = id;
      rate = r;
   }
   @Override
   public String toString() {
      return "Employee{" +
         "empId='" + empId + ''' +
         ", rate=" + rate +
         super.toString() +
         '}';
   }
   @Override
   public double earnings() {
      return rate;
   }
}

package com.mano.examples;
public class Apprentice extends StaffMember {
   public Apprentice(String n, String a, String p){
      super(n,a,p);
   }
   public double earnings(){
      return 0.0;
   }
   @Override
   public String toString() {
      return super.toString();
   }
}

package com.mano.examples;
public class ExecutiveEmployee extends Employee {
   private double bonus;
   public ExecutiveEmployee(String n, String a, String p,
         String id, double r){
      super(n,a,p,id,r);
      bonus = 0;
   }
   public void bonusReceived(double b){
      bonus = b;
   }
   public double earnings(){
      return super.earnings() + bonus;
   }
   @Override
   public String toString() {
      return "ExecutiveEmployee{" +
         "bonus=" + bonus + super.toString()+
         '}';
   }
}

package com.mano.examples;
public class RegularEmployee extends Employee{
   private int hoursWorked;
   public RegularEmployee(String n, String a, String p,
         String id, double r){
      super(n,a,p,id,r);
      hoursWorked = 0;
   }
   public void updateHours(int h){
      hoursWorked+=h;
   }
   public double earnings(){
      return rate*hoursWorked;
   }
   @Override
   public String toString() {
      return "RegularEmployee{" +
         "hoursWorked=" + hoursWorked +super.toString()+
         '}';
   }
}

多重继承

Java 不支持多重继承。多重继承是指从多个直接超类派生的类。这增加了阶级之间关系的复杂性和模糊性。如果我们考虑函数覆盖中发生的情况,这个问题是显而易见的。假设有两个类,A 和 B,每个类定义一个名为func() 的函数。现在,假设我们定义了另一个类 C,它继承自 A 和 B(多重继承),但假设这个类不会覆盖名为func() 的函数。

现在,如果我们执行以下操作:

C c = new C();
c.func();

我们可以确定调用哪个成员函数func() 吗?它是由 A 类还是 B 类定义的函数?如我们所见,C 类从 A 和 B 双重继承了这个函数。这会产生歧义,编译器正在修复以解决问题。这个问题有解决方案,但它非常复杂;因此,Java 决定通过不允许多重继承来远离问题的原因。

使用接口进行多重继承

尽管 Java 不允许多重继承,但它允许接口的多重实现。所以,在某种程度上,这个想法仍然存在。现在,什么是接口?

接口描述一组方法,但不为所有方法提供任何具体实现。我们可以借助提供方法具体实现的类来实现接口。通过这种方式,一个类可以实现多个接口,因此可以提供从一个或多个接口派生的方法的具体实现。实现一个或多个接口的类与接口类型形成is-a关系。这也意味着保证从类实例化的对象提供接口声明的功能。从此类派生的任何子类也提供相同的功能。

接口对于为许多可能不相关的类提供通用功能特别有用。因此,实现相同接口的类的对象可以响应所有接口中描述的方法调用。

从 Java 8 开始,接口通过其完整实现支持默认方法。众所周知,一个类可以实现多个接口;因此,如果多个接口包含具有相同方法签名的默认方法,则实现的类应指定要使用或重写的特定方法。

一个快速的例子

package com.mano.examples;
public interface Interface1 {
   default void func(){
      System.out.println("from interface 1");
   }
}

package com.mano.examples;
public interface Interface2 {
   default void func(){
      System.out.println("from interface 2");
   }
}

package com.mano.examples;
public class MyClass implements Interface1, Interface2 {
   public void func(){
      // Invoking Interface1 func() method
      Interface1.super.func();
      // Invoking Interface2 func() method
      Interface2.super.func();
   }
   public static void main(String[] args){
      MyClass c=new MyClass();
      c.func();
   }
}

结论

多重继承的经典问题之一称为钻石问题。这可以通过称为虚拟继承的继承机制来解决。但是,经验表明,Java并没有因为完全不允许多重继承而损失太多。事实上,Java 编译器通过为我们可以轻松解决的问题提供复杂的解决方案来摆脱它们。尽管如此,还是有一些OOP语言,如C++,支持它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/31414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用HTML实现一个静态页面(含源码)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

什么密码,永远无法被黑客攻破?

在开始本文前&#xff0c;先给大家出个解谜题&#xff0c;密码是一句英文&#xff0c;开动你的脑筋吧&#xff0c;我们在本文结尾会揭晓答案&#xff1a; 密文&#xff1a;Cigumpz yin hvq se 提示&#xff1a;和身份有关的一切 说起破译密码&#xff0c;就不得不提一个人&a…

Vue3中vite.config.js文件相关配置和mock数据配置

文章目录1. vite.config.js文件相关配置2. 路径别名3. mock数据配置1. vite.config.js文件相关配置 import { defineConfig } from vite import vue from vitejs/plugin-vue import vueJsx from vitejs/plugin-vue-jsx import path from path// https://vitejs.dev/config/ ex…

简单的股票行情演示(二) - AKShare

一、概述二、环境搭建三、使用总结 1、API文档2、数据字典3、效果截图4、后台服务四、相关文章原文链接&#xff1a;简单的股票行情演示&#xff08;二&#xff09; - akshare 一、概述 上一篇文章简单的股票行情演示&#xff08;一&#xff09; - 实时标的数据中讲述了从新浪…

web前端期末大作业 HTML+CSS+JavaScript仿安踏

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 在线商城购物 | 水果商城 | 商城系统建设 | 多平台移动商城 | H5微商城购物商城项目 | HTML期末大学生网页设计作业&#xff0c;Web大学生网页 HTML&a…

连续仨月霸占牛客榜首,京东T8呕心巨作:700页JVM虚拟机实战手册

什么是Java虚拟机 虚拟机是一种抽象化的计算机&#xff0c;通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构&#xff0c;如处理器、堆栈、寄存器等&#xff0c;还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息&#xff0c…

Linux下 生成coredump文件

一. coredump文件路径 网上很多博文说到 coredump 文件默认会在默认的目录下生成。 按照网上很多的说法&#xff0c;再运行程序就会生成core文件&#xff0c;一般路径和可执行程序一个路径。 但是&#xff0c;我尝试在 ubuntu20.04系统下&#xff0c;怎么也找不到去哪里了&a…

设计模式之美——KISS、YAGNI原则

KISS 原则算是一个万金油类型的设计原则&#xff0c;可以应用在很多场景中。它不仅经常用来指导软件开发&#xff0c;还经常用来指导更加广泛的系统设计、产品设计等&#xff0c;比如&#xff0c;冰箱、建筑、iPhone 手机的设计等等。 我们知道&#xff0c;代码的可读性和可维…

ASIFT算法过程实现 --- 配置避坑指南

常规的SIFT算法进行图像匹配的时候,只能进行两个摄像机夹角比较小的(最大是15),拍摄的图像进行相机的图像匹配,但是针对于相机之间的夹脚比较大的时候,上述的算法匹配就是会出现问题.为了解决上面的这个问题,使用了一种改进的算法匹配方式ASIFT算法进行匹配.具体这种算法的优点…

MYSQL进阶(2)

删除索引:drop Index indexName on tableName; B树叶子结点和非叶子节点都存在数据&#xff0c;那么当数据量很大的时候&#xff0c;把索引加载起来就需要很长时间 联合索引: 1)定义:是给一张表上面的多个列增加索引&#xff0c;也就是说给表上面的多个列增加索引&#xff0c;供…

MongoDB聚集分析

文章目录 聚集操作管道模式聚集MapReduce 聚集简单聚集函数小结聚集操作 聚集操作是对数据进行分析的有效手段。MongoDB 主要提供了三种对数据进行分析计算的方式:管道模式聚集分析、MapReduce聚集分析、简单函数和命令的聚集分析。 管道模式聚集 这里所说的管道类似于UNIX…

2022 APMCM亚太数学建模竞赛 C题 全球是否变暖 思路及代码实现(持续更新中)

2022 APMCM亚太数学建模竞赛 C题 全球是否变暖 思路及代码实现(持续更新中) 1 题目 全球变暖与否? 加拿大49.6C的高温为地球北纬50以上地区创造了新的气温记录&#xff0c;一周内就有数百人死于高温;美国加利福尼亚州死亡谷54.4C&#xff0c;是地球上有记录以来的最高温度;科…

Ubuntu 16.4虚拟机 配置Hadoop集群

Ubuntu 16.4 配置Hadoop集群总体步骤环境说明虚拟机配置java安装hadoop安装与配置克隆虚拟机ssh安装使用&#xff0c;免密登录更改hadoop配置结束语总体步骤 1、虚拟机配置 2、java安装 3、hadoop下载配置 4、复制虚拟机 5、ip更换&#xff0c;使用固定ip&#xff0c;并且每台…

Linux基本指令集合

Linux基本指令1&#xff0c;ls命令2&#xff0c;pwd命令3&#xff0c;whoami4&#xff0c;cd命令5&#xff0c;touch命令6&#xff0c;mkdir命令7&#xff0c;rmdir与rm命令8&#xff0c;man命令9&#xff0c;cp命令10&#xff0c;tree命令11&#xff0c;mv命令12&#xff0c;c…

智慧城市的发展趋势

智慧城市&#xff0c;是指在城市发展过程中&#xff0c;在城市基础设施、资源环境、社会民生、经济产业、市政治理领域中&#xff0c;充分利用物联网、互联网、云计算、IT、智能分析等技术手段&#xff0c;对城市居民生活工作、企业经营发展和政府行政管理过程中的相关活动&…

HTML学生个人网站作业设计:我的家乡网站设计——南宁留言表单 无js 页面8个

⛵ 源码获取 文末联系 ✈ Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 家乡旅游景点 | 家乡民生变化 | 介绍自己的家乡 | 我的家乡 | 家乡主题 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#xff1a;样式 在…

泰克/Tektronix A622电流探头型号规格参数介绍

Tektronix/泰克电流探头A622产品介绍 品牌&#xff1a;Tektronix 产地&#xff1a;美国 Tektronix泰克A622交直流电流探头适用于万用表和示波器钳型;通用BNC接口。 Tektronix/泰克电流探头A622产品特点&#xff1a; AC/DC-100kHz 50mA to 100A峰值 适用于万用表和示波器 钳形开…

HTML期末大学生网页设计作业——奇恩动漫HTML (1页面) HTML+CSS+JS网页设计期末课程大作业

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 ⚽精彩专栏推荐&#x1…

C++:函数:回调函数:还不懂回调函数来捶我

前言 不知道你是否有这样的疑问&#xff0c;我们为什么需要回调函数&#xff0c;直接调用函数不就可以了吗&#xff1f;回调函数到底有什么用&#xff1f;程序员该如何理解回调函数了&#xff1f; 这篇文章就为你解答这些问题&#xff0c;读完这篇文章后&#xff0c;你的编程…

连接肠菌与宿主的桥梁:肠菌代谢物——肠菌功能研究新篇章

人的肠道内寄居着多种微生物&#xff0c;他们统称为肠道菌群。研究表明&#xff0c;肠道菌群失衡会导致多种人体疾病&#xff0c;包括糖尿病、肿瘤、心血管疾病、神经系统疾病等。 那么肠菌是怎么对人产生影响的呢&#xff1f;答案是肠菌产生的代谢物&#xff08;1, 2&#xf…