继承、多态、组合(Java系列5)

news2025/7/7 14:48:35

目录

前言:

1.继承

1.1继承的概念

1.2继承的语法

1.3父类成员访问

1.4super关键字

1.5super和this

1.6继承关系的执行顺序

1.7继承方式

1.8final关键字

2.继承与组合

3.多态

3.1多态的概念

3.2多态实现的条件

4.重写

4.1重写的概念

4.2方法重写的规则

4.3重写和重载的区别

5.静态绑定

6.动态绑定

7.向上转型

8.向下转型

结束语:


前言:

这次小编与大家分享一下Java中的继承与多态,谈一下何为继承,怎么继承,何为多态,为什么会存在多态,以及什么是组合。

1.继承

1.1继承的概念

继承机制:是面向对象程序设计使代码可以重复使用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了有简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码的复用。同时继承最大的意义就是对代码可以进行复用。

1.2继承的语法

在java中如果要表示继承关系,需要借助extends关键字,如下所示:

修饰符 class 子类 extends 父类 {

}

注意:

  • 子类会将父类中的成员变量或者成员方法继承到子类中。
  • 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要做继承了。

1.3父类成员访问

在子类方法中或者通过子类对象访问成员时:

  • 如果访问的成员变量子类中有,优先访问自己的成员变量。
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译器报错。
  • 如果访问的成员变量与父类中成员变量与父类中成员变量同名,则优先访问自己的。
  • 成员变量访问时遵循就近原则,自己有优先自己的,如果没有则向父类中寻找。

成员方法名字相同时:

  • 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,否则编译报错。
  • 通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法中传递的参数选择合适的方法访问,如果没有则报错。 

1.4super关键字

作用:在子类方法中访问父类的成员。

代码如下所示:

public class Animal {
    public String name;
    public String sex;
    public int age;
    public void Animal(){

    }
    public void eat() {
        System.out.println(name + "正在吃!");
    }

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.age = 10;
        dog.sex = "雌性";
        dog.colour = "black";
        dog.name = "可乐";
        dog.eat();
    }
}
class Dog extends Animal {
    public String colour;
    public void eat() {
        super.eat();//调用的是父类的eat;
        System.out.println(name + "正在吃狗粮!");
    }
}


结果如下所示:

注意:

  • 只能在静态方法中使用。
  • 在子类访问父类的成员变量和方法。
  • super其实只是一个关键字,最大的作用其实就是在你写代码的时候或者是在你的阅读代码的时候能够更加方便,体现出了更好的可读性。

1.5super和this

相同点:

  • 都是java中的关键字。
  • 只能在类的非静态方法中使用,用来访问非静态成员和字段。
  • 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在。

不同点:

  • this是当前对象的引用,当前对象即调用实例的方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用。
  • 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性。
  • 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造方法中出现。
  • 构造方法中一定会存在super(…)的调用,用户没有写编译器也会调用,用户没有写编译器也会增加,但是this(…)用户不写则就是没有。

1.6继承关系的执行顺序

执行顺序:

  1. 父类静态代码块优先于子类静态代码块执行,且是最早执行的。
  2. 父类实例代码块和父类构造方法紧接着执行。
  3. 子类的实例化代码块和子类构造方法紧接着执行。
  4. 第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行。

1.7继承方式

单继承:

代码如下所示:

public class A {
}
class B extends A{
}

多层继承:

代码如下:

public class A {
}
class B extends A{
}
class C extends B{
}


不同类继承同一个类:

代码如下所示:

public class A {
}
class B extends A{
}
class C extends A{
}


多继承(不支持):

 

注意:java中不支持多继承。

1.8final关键字

final关键字可以用来修饰变量,成员方法以及类。

1.修饰变量或字段,表示常量(即不能修改)

如下所示:

 如果修改就会报错。

2.修饰类:表示次类不能被继承,如下所示。

 3.修饰方法:表示该方法不能被重写。

如果不被final修饰之前是可以进行重写的,代码如下所示:

public class Animal {
    public String name;
    public int age;
    public void eat(){
        System.out.println(name + "正在吃饭!");
    }
}
class cat extends Animal{
    @Override
    public void eat() {
        System.out.println(name + "正在吃猫粮!");
    }
}

但是在被final修饰之后就不可以在进行重写了,代码如下所示:

  

下面我们在看一个有关于final修饰的的一个例子:

代码如下所示:

public class Test1 {
    public static void main(String[] args) {
        final int[] array = {1,2,3,4};
//        array[0] = 19;①
//        array = new int[];②
    }
}

 大家现在思考一下上面代码中的①和②哪一个表达是正确的。

答案是①正确②错误,为什么呢?下面小编给大家画图进行分析一下。

2.继承与组合

组合并不是面向对象的三大特性之一,但是它和继承相似,组合也是表达类之间的关系,它也可以达到代码的复用,组合表示的是一种组成包含关系,类似于英语中的has-a的关系,下面我们来具体举一个例子让大家深切的感受一下什么是组合。

比如汽车中的一些零部件轮胎、发动机、方向盘、车载系统等等都是组成汽车的部件。

代码如下所示:

class Tire{
    //轮胎
}
class Engine{
    //发动机
}
class VehicleSystem{
    //车载系统类
}
public class Car {
    //这样就可以重复使用其中的一些属性了。
    private Tire tire;
    private Engine engine;
    private VehicleSystem vehicleSystem;
}

3.多态

3.1多态的概念

通俗的来讲就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。我们也可以这样理解:当父类引用的对象不一样的时候表现出的行为是不一样的。

3.2多态实现的条件

在java中要实现多态,必须要满足如下几个条件,缺一不可:

  1. 必须在继承体系下实现。
  2. 子类必须要对父类中方法进行重写。
  3. 通过父类的引用调用重写方法。

下面我们先来具体了解一下什么是重写和向上转型。 

4.重写

4.1重写的概念

重写也称为覆盖,重写是子类对父类的非静态、非private修饰、非final修饰、非构造方法等的实现过程进行重新编写,返回值和形参都不能改变。重写的好处在于子类可以根据需要,定义特定于自己的行为,也就是说子类能够根据需要实现父类的方法。

4.2方法重写的规则

  • 子类在重写父类的方法时,一般必须与父类方法原型一致:返回值类型、方法名(参数列表)、方法名称。
  • 被重写的方法返回值类型可以不同,但是必须是具有父子关系的。
  • 访问权限不能比父类中被重写的方法的访问权限更低,例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为protected。
  • 父类被static、final、private修饰的方法都不能被重写。
  • 重写的方法,可以使用@Override注解来显示指定,有了这个注解能帮我们进行一些合法性校验,例如不小心将方法名字拼写错了,那么此时编译器就会发现父类中没有这个方法,就会编译报错,提示无法构成重写。

当方法名字不一样时,@Override就会起到一定的监视作用来提醒程序员编写可能出错了。

 

4.3重写和重载的区别

区别点重写重载
参数列表一定不能修改必须修改
返回值类型一定不能修【除可以非构成父子关系】可以修改
访问限定符一定不能做更加严格的限制(可以降低限制)可以修改

5.静态绑定

静态绑定也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用哪个方法,典型代表函数重载。就是在编译的时候我们就已经知道调用哪个方法了。

6.动态绑定

动态绑定也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用哪个类的方法。

动态绑定的条件:

  • 向上转型。
  • 重写。
  • 通过父类引用调用这个父类和子类重写的。

7.向上转型

实际就是创建一个子类对象,将其当成父类对象来使用。通俗点讲就是把子类给父类。

语法格式:父类类型 对象名 = new子类类型();

有三种方式进行向上转型:

  • 直接赋值
  • 方法传参
  • 作为返回值

具体实现如下面的代码所示: 

class Base{
    public int age;
    public String name;

    public Base(int age, String name) {
        this.age = age;
        this.name = name;
    }
}
class Subclasses extends Base{
    public int age;
    public String name;

    public Subclasses(int age, String name) {
        super(age, name);
        this.age = age;
        this.name = name;
    }
}
public class Test3 {
    public static void fun1(Base base) {
        //2.方法传参
    }
    public static Base fun2(){
        //3.作为返回值:可以返回任意子类的对象。
        return new Subclasses(13,"旺财");
    }
    public static void main(String[] args) {
        //1.直接赋值
        Base subclasses = new Subclasses(12,"小李");
        //2.方法传参
        fun1(subclasses);
        //3.作为返回值
    }
}

注意:当发生向上转型之后,此时通过父类的引用只能访问父类自己的成员,不能访问子类的成员,即父类的访问范围变小,子类的访问返回变大。 

向上转型的优点:让代码实现更简单灵活。

向上转型的缺点:不能调用到子类特有的方法。

8.向下转型

将一个子类对象经过向上转型之后当成父类方法使用,在无法调用子类的方法,但有时候可能需要调用子类特有的方法,此时父类引用在还原为子类对象即可,即向下转型。

代码如下所示:

public class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        //被final修饰
        System.out.println(name + "正在吃饭!");
    }
//    public final void eat(){
//        //被final修饰
//        System.out.println(name + "正在吃饭!");
//    }
}
class cat extends Animal{
    public cat(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        //会报错
        System.out.println(name + "正在吃猫粮!");
    }
}
class Dog extends Animal{
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(name + "正在吃狗粮!");
    }
}
class Test {
    public static void main(String[] args) {
        Dog dog =(Dog) new Animal("可乐",12);//向下转型,但是需要强转
    }
}

向下转型用的比较少,而且不安全,万一转型失败,运行时就会抛出异常,java中为了提高向下转型的安全性,引入instanceof,如果该表达式为true,则可以安全转换。

代码如下所示:

public class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        //被final修饰
        System.out.println(name + "正在吃饭!");
    }
//    public final void eat(){
//        //被final修饰
//        System.out.println(name + "正在吃饭!");
//    }
}
class Cat extends Animal{
    public Cat(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        //会报错
        System.out.println(name + "正在吃猫粮!");
    }
}
class Dog extends Animal{
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(name + "正在吃狗粮!");
    }
}
class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("可乐",12);
        //Dog dog =(Dog) new Animal("可乐",12);//向下转型,但是需要强转
        Cat cat = new Cat("咪咪",12);
        Animal animal = cat;
        Animal animal1 = dog;
        //instanceof就是判断animal是不是引用了Cat这个对象。
        if(animal instanceof Cat) {
            cat = (Cat) animal;
            cat.eat();
        }
        //instanceof就是判断animal是不是引用了Dog这个对象。
        if(animal instanceof Dog) {
            dog = (Dog) animal;
            dog.eat();
        }
    }
}

结果如下所示:

 

结束语:

这次和大家分享了继承、多态、组合希望通过这次分享能够加深大家对java中面向对象的了解,希望对大家有所帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!) 

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

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

相关文章

前端基础(十五)_多栏布局(两列自适应布局、圣杯布局---三列布局、双飞翼布局--三列布局、等高布局)

什么是自适应? 自适应:让同一个页面自动适应不同大小的设备,从而解决为不同设备提供不同版本页面的问题。 自适应布局:解决在不同大小的设备上呈现相同网页的问题 两列自适应布局 1、Html结构中–左右两个盒子; 2、…

UT斯达康MC8638S-高安-S905-河北联通-破解刷机线刷固件包

UT斯达康MC8638S-高安-S905-河北联通-破解刷机线刷固件包 固件特点: 1、修改dns,三网通用; 2、开放原厂固件屏蔽的市场安装和u盘安装apk; 3、无开机广告,无系统更新,不在被强制升级; 4、大…

远离不恰当的运动方式,缤跃酒店满足大众对专业化、品质化健身场所的需求!

2022年,各大新闻平台关于“横纹肌溶解综合征”的新闻报道屡见不鲜,横纹肌溶解是一种因肌肉组织严重受损导致的综合征,严重的可能会出现急性肾损伤、心律失常,甚至死亡。探究原因,这些患者多是由于运动过量或不当被送入…

深度解读|NebulaGraph x 阿里云计算巢,云上构建超大规模图数据库

近期,杭州悦数科技有限公司与阿里云计算巢达成合作,NebulaGraph 作为首款图数据库产品正式入驻阿里云计算巢,为用户带来了云端一键部署企业级图数据库集群的全新体验。同时,该服务集成了多款 NebulaGraph 周边可视化图数据库管理工…

python-面向对象

目录 面向对象 封装 继承 重写 重载 多态 单下划线、双下划线、头尾双下划线说明: 面向对象 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。类变量:类变量在整个实例化的对…

ENSP防火墙进入web登陆界面

步骤 新建拓扑【选择USG6000V】然后导入USG6000V得镜像包进入到防火墙的CLI界面 账户与密码 账户:admin 密码Admin123(密码输入不会显示) 输入正确账户密码后会提醒修改密码输入 y 回车后提醒如下: 输入旧密码 输入新密码&…

基于禁忌搜索的TSP问题求解仿真输出路线规划图和收敛曲线

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 禁忌搜索(Tabu Search或Taboo Search,简称TS)是对局部搜索(LS)的一种扩展,是一种全局寻优算法,其特点是采用禁忌…

践行者访谈实录:你真的了解CMMI吗?

2022年12月21日晚8点,我参与了《践行者》访谈节目,历时2小时,就CMMI有关的话题和主持人徐东伟老师,和热心的听众进行了在线交流。节目结束后,禅道公司的小朋友们整理了文字记录如下。 相信大家对CMMI的认知或多或少地…

Android自定义ViewGroup的布局,往往都是从流式布局开始

前言 前面几篇我们简单的复习了一下自定义 View 的测量与绘制,并且回顾了常见的一些事件的处理方式。 那么如果我们想自定义 ViewGroup 的话,它和自定义View又有什么区别呢?其实我们把 ViewGroup 当做 View 来用的话也不是不可以。但是既然…

端到端网络全链路监控方案

结构日渐复杂,设备类型、设备数量逐渐增加,设备间的连接关系随之复杂化,同时随着无线网络的发展,网络中的连接关系逐渐去“线”化,如何可观、高效的对网络间复杂的连接关系进行监控和管理,成为用户不可忽视…

2022年最好用的五款设备管理软件

工厂是典型的设备密集型组织,设备固定资产具有数量多、种类多、使用周期长、使用地点分散等特征。如果依然在使用传统的手工记录数据、手工巡检、纸质维保、电话维修的方式,势必给企业带来损失。 设备是众多企业经营中支出的主要组成部分,在…

(二十)Vue之非单文件组件

文章目录基本使用一、如何定义一个组件?二、如何注册组件?三、如何使用组件?演示程序普通Vue程序单文件组件程序局部注册全局注册几个注意点1.关于组件名2.关于组件标签3.一个简写方式组件的嵌套使用关于VueComponent一个重要的内置关系&…

Shape详解

Spape详解 1.自定义背景shape 1.1gradient 1.简介 定义渐变色,可以定义两色渐变和三色渐变,及渐变样式,它的属性有下面几个2.属性 angle,只对线性渐变是有效的放射性渐变必须指定放射性的半径,gradientRadiouscentetX和…

Ubuntu安装redis服务器

官网下载redis服务器的压缩包redis-6.0.16.tar.gz 点击download 6.2.8或任意版本即可。 上传下载的压缩包到服务器或者本地虚拟机 解压压缩包,并安装gcc tar -zxvf redis-6.0.16.tar.gz解压之后可以看到redis的目录结构: 没有bin目录,而redi…

Meta CTO专访:2023年AR/VR、元宇宙的下一步怎么走

2022年对于Meta来说注定是不平凡的一年,它经历了股价大跌、万人大裁员、项目重组、季度营收首次下滑、Reality Labs季度亏损破纪录,甚至前不久Meta AR/VR业务的元老级人物、Reality Labs顾问CTO John Carck也宣布离职,这件事对于Meta甚至整个…

HEVC学习之CTU划分

一,CTU相关概念 H.265将图像划分为“树编码单元(coding tree units, CTU)”,而不是像H.264那样的1616的宏块。根据不同的编码设置,树编码块的尺寸可以被设置为6464或有限的3232或1616。 上图就是一个6464树编码块的分区示例&am…

数字ic验证|SoC的功能验证

随着设计的进行,越接近最后的产品,修正一个设计缺陷的成本就会越高。 1.功能验证概述 在IC设计与制造领域,通常所说的验证(Verification)和测试(Test)是两种不同的事 验证 在设计过程中确认…

PHP 实现PDF转图片

目录 1.环境配置: 2.实现原理: 3.安装php扩展imagick 4.安装ghostscript 5.pdf转图片 1.环境配置: 2.实现原理: Php使用扩展插件imagick进行图片处理,处理pdf时使用imagick去调用ghostscript 3.安装php扩展imag…

spring-boot如何自行写一个starter并且使用

这里说的starter是pom中引入的一系列starter包,比如spring-boot-starter-web、mybatis-plus-boot-starter等。本文先已mybatis-spring-boot-starter的使用进行说明,然后得到使用的流程(套路),然后根据该流程&#xff0…

ddim原理及代码(Denoising diffusion implicit models)

前言 之前学习了 DDPM(DDPM原理与代码剖析)和 IDDPM(IDDPM原理和代码剖析), 这次又来学习另一种重要的扩散模型。它的采样速度比DDPM快很多(respacing),扩散过程不依赖马尔科夫链。 Denoising diffusion implicit models, ICLR 2021 理论 Astract和Int…