Java继承与多态的正确打开方式

目录
  • 一.概述
  • 二.继承
    • 2.1 继承的概述
    • 2.2 继承机制
    • 2.3 类中属性,方法的继承与覆盖
      • 1.属性的继承与覆盖
      • 2.方法的继承与覆盖
    • 2.4 super 关键字
  • 三. 多态
  • 总结

一.概述

面向对象程序设计的三大原则是封装性,继承性和多态性。继承性是子类自动共享父类的数据和方法的机制,它是由类的派生功能体现的。继承具有传递性,使得一个类可以继承另一个类的属性和方法,这样通过抽象出共同的属性和方法组件新的类,便于代码的重用。而多态是指不同类型的对象接收相同的消息时产生不同的行为,这里的消息主要是对类成员函数的调用,而不同的行为是指类成员函数的不同实现。当对象接收到发送给它的消息时,根据该对象所属的类,动态选用在该类中定义的实现算法。

二.继承

2.1 继承的概述

在现实中存在很多如图所示的关系:

出租车,卡车和公交车都是汽车的一种,分别拥有相似的特征。例如,引擎的数量,外观颜色等。它们拥有相似的行为,如刹车和加速的功能。但是每种不同的交通工具又有自己的特征,如公交车拥有和其他交通工具不同的特性和行为——最大载客数量和到指定站点要报站的特点,而卡车的主要功能是送货物,也就是载货和卸货,因此拥有最大载重量的特性。

在面向对象的程序设计中该怎样描述现实世界的这种状况呢?这就用到继承的概念。

所谓继承,就是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。已有的类一般称为父类(基类或超类),这个过程也称为类的派生。由基类产生的新类称为派生类或子类,派生类同样可以作为基类再派生新的子类,这样就形成了类间的层次结构。

基类和派生类类的关系如下:

  • 基类是派生类的抽象(基类抽象了派生类的公共特征)。
  • 派生类是对基类的扩展。
  • 派生类和基类的关相当于“是一个(is a)”的关系,即派生类是基类的一个对象,而不是“有(has)”的关系,即类的对象包含一个或多个其他类的对象作为该类的属性。

2.2 继承机制

定义教师类,其中一类教师为Net教师,属性为姓名,所属部门,方法为授课,自我介绍。

public class NetTeacher {
   private String name;
   private String school;
   public NetTeacher(String myName,String mySchool){
      name = myName;
      school = mySchool;
   }
   public void giveLession(){
      System.out.println("启动 VS2021 ");
      System.out.println("知识点讲解");
      System.out.println("总结提问");
   }
   public void introduction(){
      System.out.println("大家好!我是" + schoool + "的" + name + " 。");
   }
}

定义教师类,其中一类教师为Java教师,属性为姓名,所属部门,方法为授课,自我介绍。

public class JavaTeacher {
   private String name;
   private String school;
   public JavaTeacher(String myName,String mySchool){
      name = myName;
      school = mySchool;
   }
   public void giveLession(){
      System.out.println("启动 IDEA2021 ");
      System.out.println("知识点讲解");
      System.out.println("总结提问");
   }
   public void introduction(){
      System.out.println("大家好!我是" + schoool + "的" + name + " 。");
   }
}

在程序处理中,发现两个类的定义非常相似,有很多相同点,如教师的属性姓名,所属部门类似,类的方法也基本相同。

针对这种情况,将Java教师类和Net教师类的共性抽取出来,形成父类Teacher类,使得Net教师和Java教师成为Teacher类的子类,则子类继承父类的基本属性和方法,就简化了子类的定义。上述代码可以修改如下:

public class Teacher {
   private String name;
   private String school;
   public Teacher(String myName,String mySchool){
      name = myName;
      school = mySchool;
   }
   public void giveLession(){
      System.out.println("知识点讲解");
      System.out.println("总结提问");
   }
   public void introduction(){
      System.out.println("大家好!我是" + schoool + "的" + name + " 。");
   }
}

子类JavaTeacher:
public class JavaTeacher extends Teacher {
   public JavaTeacher(String myName,String mySchool){
      super(myName,mySchool);
   }
   public void giveLession(){
      System.out.println("启动 IDEA2021 ");
      super.giveLession;
   }

子类NetTeacher:
public class NetTeacher extends Teacher {
   public NetTeacher(String myName,String mySchool){
      super(myName,mySchool);
   }
   public void giveLession(){
      System.out.println("启动 VS2021 ");
      super.giveLession;
   }

子类自动继承父类的属性和方法,子类中不再存在重复代码,从而实现代码的重用。

通过关键字 extends,分别创建父类 Teacher 的子类 JavaTeacher 和 NetTecher 。子类继承父类所有的成员变量和成员方法,但不能继承父类的构造方法。在子类的构造方法中,可使用语句super (参数列表)调用父类的构造方法,如子类构造方法中的语句 super(myName,mySchool)。

extends 说明要构建一个新类,该类从已存在的类派生而来。派生的定义过程,实际是经历了以下几个过程:

  • 子类继承父类中被声明为 public 和 protected 的成员变量和成员方法,但是不能继承被声明为 private 的成员变量和成员方法。
  • 重写父类成员,包括数据成员和成员函数。如果子类声明了一个与父类成员函数相同的成员函数,子类中的新成员则屏蔽了父类同名成员,类似函数中的局部变量屏蔽了全局变量,称为同名覆盖(Overriding)。
  • 定义新成员。新成员是派生类自己的新特性。派生类新成员的加入使得派生类在功能上有所发展。
  • 必须在派类中重写构造方法,因为构造方法不能继承。

2.3 类中属性,方法的继承与覆盖

1.属性的继承与覆盖

子类可以继承父类的所有非私有属性。

子类也可以覆盖继承的成员变量,对于子类可以从父类继承的成员变量,只要子类中定义的成员变量和父类中的成员变量同名,子类就覆盖了继承的成员变量。

当子类执行它自己定义的方法时,所操作的就是它自己定义的数据成员,,从而覆盖父类继承来的数据成员。

2.方法的继承与覆盖

父类中非私有( private )方法可以被子类所继承。

在子类继承父类的成员方法时,应注意一下两项:

  • 子类不能访问父类的 private 成员方法,但子类可以访问父类的 piblic ,protected 成员方法。
  • 访问 protected 时,子类和同一包内的方法都能访问父类的 protected 成员方法,但其他方法不能访问。

方法的覆盖是指子类中定义一个方法,并且这个方法的名字,返回类型,参数列表与父类继承的方法完全相同。

2.4 super 关键字

子类不能继承父类的构造方法。

如果基类中没有默认构造方法或希望调用带参数的基类构造方法,要使用关键字 super 来显示调用基类构造方法。使用关键字 super 调用基类构造方法的语句,必须是子类构造方法的第一个可执行语句。调用基类构造方法时,传递的参数不能是关键字 this 或当前对象的非静态成员。

super 关键字主要应用于继承关系实现子类对父类方法的调用,包括对父类构造方法和一般方法的调用。具体使用方法如下:

(1)子类的构造方法如果要引用 super ,必须把 super 放在构造方法的第一个可执行语句。例如:

public CommonEmployee (String name,double bonus){
   super (name);                         //通过 super () 的调用,给父类的数据成员赋初值
   this.bonus = bonus;                   // this 指当前对象
   System.out.println("子类构造方法的调用");
}

(2)在 Java 中,有时还会遇到子类中的成员变量或方法与父类中的成员变量或方法同名。同名子类中的成员变量或方法名优先级高,所以子类中的同名成员变量或方法覆盖了父类的成员变量或方法,但是我们如果想要使用父类中的这个成员变量或方法,就需要用到 super .

(3)可以用 super 直接传递参数。见下面代码:

public class Person {
    Person(){
        prt("A Person.");
    }
    Person(String name){
        prt("A person name is:" + name);
    }
    public static void prt(String s){
        System.out.println(s);
    }
}

public class Chinese extends Person {
    Chinese(){
        super();                     //调用父类无形参构造方法
        prt("A chinese");         //调用父类的方法prt
    }
    Chinese(String name){
        super(name);                 //调用父类具有相同形参的构造方法
        prt("his name is:" + name);
    }
    Chinese(String name,int age){
        this(name);                  //调用当前具有相同形参的构造方法
        prt("his age is:" + age);
    }

    public static void main(String[] args) {
        Chinese cn = new Chinese();
        cn = new Chinese("Kevin");
        cn = new Chinese("Jhone",21);
    }
}

 程序分析如下:

  • main()中首先构建Chinese的第一个对象cn, 语句cn = new Chinese()调用子类无参的构造方法Chinese(),在构造方法中super()语句调用父类的无参构造方法Person(),在父类无参的构造方法中调用父类的方法prt(),程序输出结果A Person,接下来返回子类的构造方法的调用处,继续执行下面的语句pr("A chinese."),则调用父类的方法prt输出结果A chinese.结束第一条语句。
  • 程序继续执行第二条语句cn = new Chinese("kevin");此时调用子类具有一 个参数参的构造方法Chinese(name),在构造方法中super(name)语句调用父类的有参构造方法prt("A person name is:"+ name),程序输出结果A person name is:kevin,接下来返回子类的构造方法的调用处,继续执行下面的语句prt("his name is:"+ name),则调用父类的方法prt输出结果his name is:kevin,结束第二条语句。
  • 接下来程序继续执行第三条语句cn = new Chinese("Jhone,"22);程序执行时先调用子类具有两个参数参的构造方法Chinese(name, age), 在构造方法中this ( name )语句则调用的是当前具有相同参数的构造方法,即调用子类具有一个参数参的构造方法Chinese(name),接下来调用父类的有参构造方法Person(name),为父类的name进行初始化,再接下来在父类有参的构造方法中调用父类的方法prt("A person name is:"+ name),程序输出结果A person name is: Jhone,接下来返回子类的构造方法的调用处,继续执行下面的语句prt("his name is:"+ name),则调用父类的方法prt输出结果his name is: Jhone,调用结束后程序返回子类构造方法Chinese(name,age)执行语句prt("his age is:"+ age); 输出结果his age is:22,结束第二条语句。

三. 多态

多态是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。

对面向对象来说,多态分为编译时多态和运行时多态。其中编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是大家通常所说的多态性。

Java  实现多态有 3 个必要条件:继承、重写和向上转型。只有满足这 3 个条件,开发人员才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而执行不同的行为。

  • 继承:在多态中必须存在有继承关系的子类和父类。
  • 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
  • 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 浅谈Java封装、继承、多态特性

    目录 1.封装 2.继承 3.多态 4.上代码,效果运行放在最后 1.封装 什么是封装,谈谈自己对封装的理解,封装就是将类的信息(比如说类的属性)隐藏在类的内部,不允许外部程序直接访问.此时就要提到一个关键字private,他是一个权限修饰符,可以用来修饰成员(变量和方法),保护成员不被其他别的类来使用,如果需要被其他类来使用,那么需要提供对应的操作:a.提供get变量名()方法,用于获取成员变量的值 b.提供set变量名(参数),用于设置成员变量的值,同样也和get方法一样,都是用public

  • Java初学之继承与多态

    目录 在程序中声明包的语法: Java继承语法格式: 什么是重写呢?: 多态应用: 引用变量的强制类型转换 instanceof 运算符 总结 首先我们如果要使用Java中存在的包,可以程序中使用import语句导入包.包说通俗点就是一个 文件夹,为了方便管理. 在程序中声明包的语法: package <包名> 注意:声明一个包的语句必须写在类中的第一行. 在程序中导入包的格式: import <包名>.<类名> 重点来了,继承! 继承是面向对象程序设计的一个重要特征,

  • java面向对象继承与多态介绍

    目录 一.概述 二.继承 2.1 继承的概述 2.2 继承机制 2.3 类中属性,方法的继承与覆盖 2.4 super 关键字 三. 多态 总结 一.概述 面向对象程序设计的三大原则是封装性,继承性和多态性.继承性是子类自动共享父类的数据和方法的机制,它是由类的派生功能体现的.继承具有传递性,使得一个类可以继承另一个类的属性和方法,这样通过抽象出共同的属性和方法组件新的类,便于代码的重用.而多态是指不同类型的对象接收相同的消息时产生不同的行为,这里的消息主要是对类成员函数的调用,而不同的行为是指

  • 新手初学Java继承、封装与多态

    目录 面向对象的三大核心特性 封装 继承 单继承 继承的优缺点 super关键字 super调用父类构造方法 super访问父类成员 super和this的区别 多态 instanceof关键字 方法重载 方法重写 抽象类 接口 定义接口 实现接口 总结 面向对象的三大核心特性 面向对象开发模式更有利于人们开拓思维,在具体的开发过程中便于程序的划分,方便程序员分工合作,提高开发效率.面向对象程序设计有以下优点. 可重用性:代码重复使用,减少代码量,提高开发效率.下面介绍的面向对象的三大核心特性(

  • JAVA回顾:封装,继承,多态

    目录 知识点回顾 封装 继承 super注意点: Vs this: 前提: 构造方法 多态 总结 知识点回顾 封装 封装(有时称为数据隐藏)是与对象有关的一个重要概念.从形式上来看,封装不过是将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式.对象中的数据称为实例域,操作数据的过程称为方法.对于每个特定的类实例(对象)都有一组特定的实例域值.这些值的集合就是这个对象的当前状态.无论何时,只要向对象发送一个消息,它的状态就有可能改变. 实现封装的关键在于绝对不能让类中的方法直接地访问

  • Java继承与多态的正确打开方式

    目录 一.概述 二.继承 2.1 继承的概述 2.2 继承机制 2.3 类中属性,方法的继承与覆盖 1.属性的继承与覆盖 2.方法的继承与覆盖 2.4 super 关键字 三. 多态 总结 一.概述 面向对象程序设计的三大原则是封装性,继承性和多态性.继承性是子类自动共享父类的数据和方法的机制,它是由类的派生功能体现的.继承具有传递性,使得一个类可以继承另一个类的属性和方法,这样通过抽象出共同的属性和方法组件新的类,便于代码的重用.而多态是指不同类型的对象接收相同的消息时产生不同的行为,这里的消

  • Java 继承与多态的深入理解

    Java 继承与多态的深入理解 1.  什么是继承,继承的特点? 子类继承父类的特征和行为,使得子类具有父类的各种属性和方法.或子类从父类继承方法,使得子类具有父类相同的行为. 特点:在继承关系中,父类更通用.子类更具体.父类具有更一般的特征和行为,而子类除了具有父类的特征和行为,还具有一些自己特殊的特征和行为. 在继承关系中.父类和子类需要满足is-a的关系.子类是父类. 表示父类和子类的术语:父类和子类.超类和子类.基类和派生类,他们表示的是同一个意思. 2.  为什么需要继承?什么时候应该

  • Spring原生Rpc六种的正确打开方式实现示例

    目录 前言 什么是Rpc? Spring中的Rpc 定义服务接口 调用服务代码 WEBSERVICE的RPC实现 服务提供者 服务实现 服务暴露 服务消费者 HTTP的RPC实现 服务提供者 服务实现 服务暴露 服务消费者 文末结语 前言 在java生态圈谈到Rpc,很多人可能就会想到Dubbo.Motan.Grpc等框架.但是你知道吗?作为Java编程全家桶的Spring已经内置了多种RPC的实现方式,可以直接使用.存在即合理,有些场景下其实并不需要Dubbo,Grpc等重量级的RPC组件,那

  • Java 继承与多态超详细梳理

    目录 一.继承 1.继承的概念 2.继承的语法 3.父类成员访问 (1)子类中访问父类的成员变量 (2)子类中访问父类的成员方法 4.super关键字 5.子类构造方法 6.super和this 7.代码块执行顺序 8.继承方式 9.final关键字 10.继承和组合 二.多态 1.向上转型 2.重写 3.多态 一.继承 1.继承的概念 继承机制:是面向对象程序设计是代码可以复用的最重要手段,允许程序员在保持原有类特性的基础上进行扩展,增加新的功能,产生的新类,成为派生类/子类.继承主要解决的问

  • TypeScript中extends的正确打开方式详解

    目录 前言 extends第一式:继承 类继承类 接口继承接口 接口继承类 extends第二式:三元表达式条件判断 普通的三元表达式条件判断 情况一:Type1和Type2为同一种类型. 情况二:Type1是Type2的子类型. 情况三: Type2类型兼容类型Type1. 带有泛型的三元表达式条件判断 extends第三式:泛型约束 前言 最近完整地看了一遍TypeScript的官方文档,发现文档中有一些知识点没有专门讲解到,或者是讲解了但却十分难以理解,因此就有了这一系列的文章,我将对没有

  • vue-cli + sass 的正确打开方式图文详解

    关于在vue-cli搭建的项目中怎么配置sass,网上搜到的基本是这种答案: 但是我认为,直接将样式写在每个单文件的<style>里,是十分不明智的做法.且不说node-sass安装过程的各种坑,内嵌的<style>也让组件显得十分混乱.想象一下你在修改某个methods时必须拖动滚轮穿越几十上百行的css代码,又或者为了修改一组样式,却找不到对应的css文件,因为它们散布在vue文件里... 在我看来,正确的做法应该是单独管理sass文件,然后在main.js中直接引入编译好的c

  • 基于python的多进程共享变量正确打开方式

    多进程共享变量和获得结果 由于工程需求,要使用多线程来跑一个程序.但是因为听说python的多线程是假的,于是使用多进程,反正任务需要共享的参数少. 查阅资料,发现实现多进程主要使用Multiprocessing,有两种方式,一种是Process,另一种是Pool. p = Process(target=fun,args=(args)) 再通过p.start()来启动一个子进程,通过p.join()方法来使得子进程运行结束后再执行父进程. 但是这样很烦,还要写个for 循环来开n个线程和join

  • 基于Python log 的正确打开方式

    保存代码到文件:logger.py import os import logbook from logbook.more import ColorizedStderrHandler import smtplib LOG_DIR = os.path.join('log') if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR) def get_logger(name='test', file_log=False): logbook.set_date

  • 云开发 VSCode 插件 Cloudbase Toolkit 的正确打开方式及应用场景分析

    什么是 Cloudbase Toolkit Tencent CloudBase Toolkit 是云开发的 VS Code(Visual Studio Code)插件.该插件可以让您更好地在本地进行云开发项目开发和代码调试,并且轻松将项目部署到云端. Cloudbase Toolkit 将项目创建.函数上传.函数更新.函数本地调试等功能集成在 VSCode 的本地调试环境中,开发者可以通过简单的点击,完成云函数的更新.上传.同步等功能. 和 Cloudbase Cli 相比,Cloudbase

  • python中四舍五入的正确打开方式

    round()函数 (注意:下面的我也不清楚是否正确,我只是发表一下我的观点) 对于简单的舍入运算,使用内置的 round(value, ndigits) 函数即可 强烈建议不要去深究,就直接得结果就好 ndigiths可以为正数,也可以为负数,还可以为0,可以为空 n:就是精确到第n位小数,对整数没有影响,1为精确到十分位(注意:小数就是从十分位往后推的) -n:就是精确到整数位,-1为精确到十位,然后就是百位千位-有小数位就全舍掉,不管多大,但会保留一个为0的小数位 0:精确到个位,但会保留

随机推荐