Java:继承和多态

news2025/7/22 5:25:27

文章目录

  • 前言
  • 一、继承
    • 1.继承概念
    • 1.1 继承的语法
    • 1.2 父类成员方法
    • 1.2.1 子类访问父类的成员变量
    • 1.2.2 子类访问父类的成员方法
    • 1.3 super、this 关键字
    • 1.4 子类构造方法
    • 1.5 继承的方式
    • 1.6 final 关键字
    • 1.7 继承与组合
  • 二、多态
    • 2.1 多态的概念
    • 2.2 多态实现的条件
    • 2.3 对重写的认识
      • 2.3.1 重写与重载
    • 2.4 向上转型与向下转型
      • 2.4.1 向上转型
      • 2.4.2 向下转型
    • 2.5 避免在构造方法中调用重写方法
  • 总结

✨✨✨学习的道路很枯燥,希望我们能并肩走下来!

编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得枯燥乏味,像对待任务似的应付它。但你如果深入探索,就会发现其中的奇妙,了解许多所不知道的原理。知识的力量让你沉醉,甘愿深陷其中并发现宝藏。


前言

本篇是对继承的介绍,super的使用与this的区别,final关键字,继承方式的讲解和多态的实现,重写,向上/下转型等。如有错误,请在评论区指正,让我们一起交流,共同进步!


本文开始

一、继承

1.继承概念

继承:用于对共性进行抽取,实现代码的复用。
继承机制:允许程序员在保持原有类特性的基础上进行拓展,增加新的功能。这样产生类称为派生、子类。原有的类称为父类,基类,超类。

1.1 继承的语法

使用extends关键字

修饰符 class 子类 extends 父类 {
}

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

1.2 父类成员方法

1.2.1 子类访问父类的成员变量

1.子类和父类不存在同名方法

class Base {
    int a = 1;
    int b;
}
class Derived extends Base {
    int c;
    public void func() {
        System.out.println(a);//访问继承父类的a
        System.out.println(c);//访问子类自己的c
    }
}

2.子类和父类成员变量同名

class Base {
    int a;
    int b;
    int c = 9;
}
class Derived extends Base {
    int c = 10;
    public void func() {
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
      //System.out.println(d);//报错,子类父类都没有定义
    }
}

子类和父类有同名变量,依照就近原则,先使用子类自己的变量,子类没有在找父类的变量!

在这里插入图片描述

【注】在子类方法(对象)中,访问成员:
1.访问成员变量子类中有,就先访问子类自己的
2.访问成员变量子类中无,就先访问父类的,父类没有,就报错
3.访问成员变量父类子类同名的成员变量,就先访问子类自己的

1.2.2 子类访问父类的成员方法

1.子类和父类成员方法名相同

class Base {
    public void methodBase() {
        System.out.println("Base里的methodBase()");
    }
}
class Derived extends Base {
    public void menthodBase() {
        System.out.println("Derived里的menthodBase()");
    }
}

2.子类和父类成员方法名不同
优先访问自己的成员方法,自己没有时再到父类中找,如果父类中也没有则报错。

class Base {
    int a;
    int b;
    int c = 9;
    public void methodBase() {
        System.out.println("Base里的methodBase()");
    }
}
class Derived extends Base {
    int c = 10;
    public void methodDerived() {
        System.out.println("Derived()");
    }
}

【小结:】
1.子类对象访问父类与子类的 同名方法,根据调用方法传递参数列表选择访问(重载),没有则报错
2.子类对象访问父类与子类的 不同名方法时,优先在子类中找,找不到,在父类找,找到访问,找不到报错

1.3 super、this 关键字

super作用 : 子类和父类中存在相同的成员时,使用super,super可以在子类方法中访问父类的成员。

super调用在子类中调用了父类的成员变量和方法

class Base {
    int a;
    int b;
    int c = 9;
    public void methodBase() {
        System.out.println("Base里的methodBase()");
    }
}
class Derived extends Base {
    int c = 10;
    public void methodBase() {
        System.out.println("Derived里的menthodBase()");
        super.methodBase();
    }
    public void func() {
        System.out.println("Derived中的 c = " + c);
        System.out.println("Base中的 c = " + super.c);
    }
}

代码结果:

在这里插入图片描述

【注】
1.在子类方法中,如果想要明确访问父类中成员时,借助super关键字
2.只能在非静态方法中使用


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

super,this相同点:
1.只能在类的非静态方法中使用,用来访问非静态成员方法和字段
2.在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在


1.4 子类构造方法

子类对象构造时,需要先调用父类构造方法,然后执行子类的构造方法。(先构造父类,在构造子类)

1.父类定义无参构造方法或默认构造方法,在子类构造方法中第一行默认含有super()调用;(父类或者子类不写构造方法,默认父类子类无参构造)

class A {
    public A() {
        System.out.println("A的无参构造");
    }
}
class B extends A{
    public B() {
        super();//调用父类无参构造
        System.out.println("B的无参构造");
    }
}
public class Test {
    public static void main(String[] args) {
        new B();
    }
}

代码结果:

在这里插入图片描述

2.如果父类含有带参数的构造方法,此时子类构造需要选择合适的父类构造方法调用;(父类如果写了含参数的构造方法,则就没有无参的构造方法,如果需要用需要自己写无参构造)
3.在子类构造方法中,super()调用父类构造,必须是子类构造函数中的第一条语句
4.super()只能在子类构造方法中出现一次,并且不能和this同时使用;(this(),super()在构造方法中都必须在第一行,所有不能共存)

1.5 继承的方式

1.单继承:
B =》A

class A {
...
}
class B extends A{
}

2.多层继承
C =》B =》A

class A {
....
}
class B extends A{
....
}
class C extends B {
 ....   
}

3.不同类继承同一个类
同一包中不同java文件中

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

4.多继承(不支持)=》err
JAVA中不支持多继承

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

1.6 final 关键字

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

final int a = 10;
    a = 20;

2.final 修饰类:表示类不能被继承

final public class A {
}
//err
public class B extends A {
}

3.final 修饰方法:不能被重写

1.7 继承与组合

组合:仅仅将一个类的示例作为另一个类的字段,为了达到代码的重用

继承:表示对象之间是 is-a 的关系,比如:狗是动物,猫是动物
组合:表示对象之间是 has-a 的关系,比如:学校作为类,学生和老师都是学校里的示例字段

class Stduent {
...
}
class Teacher {
...
}
class School {
    Stduent[] stduents = new Stduent[3];
    Teacher[] teachers = new Teacher[3];
}
public class TestDemo {
    public static void main(String[] args) {
        School school = new School();
    }
}

二、多态

2.1 多态的概念

多态 :为了完成某个行为,不同的对象去完成时会产生不同的状态。(同一件事,发生在不同对象上,会产生不同的结果)

例如:动物吃东西
狗吃狗粮,鸟吃鸟粮,鱼吃鱼粮。同样是吃饭的行为,但他们吃的什么却不同。

2.2 多态实现的条件

Java实现多态的条件

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

多态示例图示:
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

在这里插入图片描述

在这里插入图片描述
发生重写,子类发生不同的状态,7吃狗粮, qq吃鸟粮
在这里插入图片描述

我们下面讲解为什么重写后会调用子类的重写的eat()方法,为什么不调用父类的?

2.3 对重写的认识

重写(override):也称为覆盖。即外壳不变,核心重写! 也就是说子类能够根据需要实现父类的方法。

重写是子类对 ①父类非静态、②非private修饰,③非final修饰,④非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。
被final修饰的方法称为密封方法。

重写规则:

  1. 子类重写父类,方法的返回值类型、方法名、参数列表相同
  2. 具有父子类关系,被重写的方法返回值类型可以不同
  3. 子类访问权限要 大于 父类的访问权限;父类方法是public修饰的,子类重写不能是protected
  4. 父类中被①static②private③构造方法都不能被重写
  5. 重写的方法,可以使用 @Override 来注释,可以帮助我们进行合法性校验。如果重写的方法名拼写错误,编译器就会发并报错。

发生动态绑定:编译的时候不确定,在从重写的时候,调用子类的重写方法
静态绑定: 重载,编译的时候已经确定调用那个方法

问题1:为什么重写后会调用子类的重写的eat()方法,为什么不调用父类的?
这是因为在重写的时候会发生动态绑定,会在程序运行的时候,帮我们调用了重写的方法。

问题2:为什么不是编译的时候调用子类的重写方法呢?
我们可以通过class字节码文件来看一下
找到字节码文件,通过命令行打开,输入:javap - c 文件名

在这里插入图片描述
通过查看字节码文件可知,编译时调用的还是父类的eat()方法。

2.3.1 重写与重载

在这里插入图片描述

2.4 向上转型与向下转型

2.4.1 向上转型

向上转型:父类对象引用子类的对象
语法格式:父类类型 对象名 = new 子类类型();
向上转型缺点:不能调用子类特有的方法

三种使用:
1.直接赋值
Animal animal = new Dog();

public static void main(String[] args) {
        Animal animal = new Dog();
        //animal这个引用只能引用Animal这个类里面的方法
        //发生向上转型后:父类的引用只能访问父类自己的成员。不能访问到子类特有的成员
        //相对于子类访问的范围更大一些
        animal.name = " 7 ";
        animal.eat();

        //animal.wang();不能访问子类的方法
        Animal animal1 = new Bird();
        //向上转型。前提: Bird继承Animal
        animal1.name = "qq";
        animal1.eat();
    }

2.方法传参
func(dog)

 public static void func(Animal animal) {
        //方法传参
    }
    public static void main(String[] args) {
        Dog dog = new Dog();
        func(dog);
    }

3.返回值
Animal animal = func2();

public static Animal func2() {
        //返回值
        return new Dog();
    }

2.4.2 向下转型

向下转型:为了调用子类特有的方法,我们可以将父类引用还原为子类对象

public static void main(String[] args) {
        Animal animal = new Dog();
        //向下转型:不安全
        System.out.println("=========");
        Bird bird = (Bird) animal;
        bird.fly();
    }

向下转型不安全,编译没问题,但是运行时会报错

在这里插入图片描述

代码修改:

public static void main(String[] args) {
        Animal animal = new Dog();
        //向下转型:不安全,需要判断使用关键字instanceof
        //父类的类型给到子类
        Dog dog = (Dog) animal;
        dog.name = "7";
        dog.wang();
        
        System.out.println("=========");
        if(animal instanceof Bird) {
        //判断animal是不是引用了Bird的对象
            Bird bird = (Bird) animal;
            bird.fly();
        }

    }

判断后结果就不会报错了

在这里插入图片描述

2.5 避免在构造方法中调用重写方法

class B {
    public B() {
// do nothing
        func();
    }
    public void func() {
        System.out.println("B.func()");
    }
}
class D extends B {
    private int num = 1;
    @Override
    public void func() {
        System.out.println("D.func() " + num);
    }
}
public class TestDemo {
    public static void main(String[] args) {
        D d = new D();
    }
}

代码结果:

在这里插入图片描述

结果可知:
num值为0,并没有赋值为1,这是因为在构造器中调用方法所导致的;
代码执行过程:
1.构造D对象的同时调用B构造方法
2.B 的构造方法调用func()方法,此时会触发动态绑定,会调用D中的func()
3.此时D 对象自身还没有构造,此时num处于为初始化状态,值默认0,如果具备多态性,num的值应该是1

【注】尽量不要在构造器中调用方法!!!
当在父类的构造方法当中,去调用父类和子类重写的方法的时候,会发生动态内存绑定,会调用子类重写的同名方法,而产生问题!

总结

✨✨✨各位读友,本篇分享到内容如果对你有帮助给个👍赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!

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

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

相关文章

Canvas 基础使用

一、基本的画布功能 创建 <canvas>元素时至少要设置 width 和 height 属性&#xff0c;这样才能告诉浏览器在多大面积上绘图。出现在标签包裹里的内容会在浏览器不支持 <canvas>元素时显示。比如&#xff1a; <canvas id"drawing" width"200&q…

PumpkinBook Reading(一)

绪论 基本术语 “算法”是指从数据中学得“模型”的具体方法&#xff0c;“算法”产出的结果称为“模型”&#xff0c;通常是具体的函数或者可抽象地看作为函数。 样本&#xff1a;也称为“示例”&#xff0c;是关于一个事件或对象的描述。因为要想让计算机能对现实生活中的事…

【Python开发】Flask开发实战:个人博客(三)

Flask开发实战&#xff1a;个人博客&#xff08;三&#xff09;在【Python开发】Flask开发实战&#xff1a;个人博客&#xff08;一&#xff09; 中&#xff0c;我们已经完成了 数据库设计、数据准备、模板架构、表单设计、视图函数设计、电子邮件支持 等总体设计的内容。 在【…

公众号裂变拉新,以婴儿辅食为诱饵,实现低成本获客!

大家好~我是娜娜 今天来给大家拆解一个关于食品行业精选公众号增长案例&#xff0c;通过公众号裂变拉新&#xff0c;任务拉新人数5000&#xff0c;留存率达到85%&#xff0c;活动裂变率达到1100.86%。活动数据也还在持续的上升当中。 该公众号的目标人群是新手爸妈&#xff0…

【Java】SpringBoot应用简单示例

SpringBoot应用简单示例SpringBoot应用简单示例HelloWorld搭建项目ResponseBody的作用ComponentScan排除扫描beanSpringBoot集成日志SpringBoot日志初始化原理消息转换器拦截器过滤器操作数据库Spring Data JpaDruid数据源Mybatis-Plus事务处理操作缓存AOP相关概念栗子定时任务…

C语言解析JSON源码

它与 XML 的地位差不多&#xff0c;但就笔者而言&#xff0c;笔者更喜欢 JSON 的风格&#xff0c;因为它更符合我们的思维习惯&#xff0c;同样一份数据&#xff0c;JSON 格式的就是比 XML 要清晰明了一些。 最近笔者需要在 C语言 上解析 JSON 格式&#xff0c;在网上一顿找&am…

XC5VLX30T-2FF323I Virtex-5 LXT FPGA IC 产品参数

概述 Virtex-5 FPGA有-3&#xff0c;-2&#xff0c;-1速度等级&#xff0c;其中-3具有最高的性能。Virtex-5 FPGA直流和交流特性指定为商业和工业级别。除工作温度范围外&#xff0c;除非另有说明&#xff0c;所有直流和交流电气参数对于特定转速等级是相同的(即-1转速等级的工…

一夜登顶GitHub!字节内网数据结构与算法刷题笔记,看完直呼卧槽

网络上流传着一句段子“程序员两条腿&#xff0c;一条是算法&#xff0c;一条是英文&#xff0c;想跑的更远&#xff0c;这两条腿都不能弱”。英文&#xff0c;我们暂且不谈&#xff0c;我们先来谈谈算法。 算法之难&#xff0c;在于将精巧的逻辑&#xff0c;通过合适的数据结…

2 分钟,教你用 Serverless 每天给女朋友自动发土味情话

作者&#xff1a;安可 Serverless 简介 Serverless&#xff0c;中文意思是 “无服务器”&#xff0c;所谓的无服务器并非是说不需要依靠服务器等资源&#xff0c;而是说开发者再也不用过多考虑服务器的问题&#xff0c;可以更专注在产品代码上&#xff0c;同时计算资源也开始…

如何根据自己的SCI论文,匹配适合的期刊? - 易智编译EaseEditing

如何选择合适的目标期刊是需要慎重对待的问题&#xff0c;它决定了你论文的发表速度和被认可度。 可以遵循以下几个步骤来考虑&#xff1a; 1、从你论文的参考文献中选择合适的期刊&#xff08;如果引用文献较少&#xff0c;也可以从引文的参考文献中进行筛选&#xff09;&…

成功解决:ModuleNotFoundError: No module named ‘amp_C‘

在使用transformers时&#xff0c;在调用Trainer的时候遇到了这个问题&#xff0c;原因是apex包有问题&#xff0c; 这里有解决apex安装包的多一些教程 https://blog.csdn.net/Xidian185/article/details/122745427 https://blog.csdn.net/weixin_45225975/article/details/119…

倍福TwinCAT3中使用久同伺服

目录 一、测试设备说明 二、伺服通电和参数设置 1、恢复出厂参数设置 2、恢复出厂&#xff0c;重启后 3、伺服自己点动操作 4、增益、刚度调整 5、伺服零位设定 6、伺服转动一圈编码器脉冲量设定 7、参数保存 三、伺服操作面板 四、TwinCAT3工程配置 1、XML文件 2、…

【元宇宙欧米说】打造艺术与技术构建的交互式数字旅程

Web3 to Earn项目如何扩大应用功能和场景&#xff1f;在Web3时代怎么才能以更新颖、有趣的方式追赶潮流&#xff1f;各Web3领域项目及应用如何进行功能外延以满足用户需求&#xff1f; 11月17日晚上九点&#xff0c;ZenCats项目管理员Fred将以“打造艺术与技术构建的交互式数字…

编码格式转换方法

今天项目上遇到了需要将 SJIS(Shift-JIS) 格式与 UTF8 格式相互转换问题。 首先看一个编码格式问题引发的乱码现象&#xff0c;新建下面的文本文档&#xff0c;然后更名为 test.bat。 echo off echo test chinese character view 测试中文字符显示 pause双击运行 用 chcp 查…

正版授权| iObit Uninstaller 12 Pro 专业卸载器工具

前言 专业的Win系统卸载程序&#xff0c;它可以轻松删除不需要的程序&#xff0c;插件和Windows应用程序&#xff0c;还可以对电脑旧的应用一键更新。安装监视器会检测并记录安装中的所有系统更改&#xff0c;以确保在将来彻底卸载时可以还原所有更改。 功能特点 安装监视器 …

1053 Path of Equal Weight

Given a non-empty tree with root R, and with weight Wi​ assigned to each tree node Ti​. The weight of a path from R to L is defined to be the sum of the weights of all the nodes along the path from R to any leaf node L. Now given any weighted tree, you a…

QT获取计算机硬件信息

一、项目介绍 本文介绍利用QProcess获取计算机的CPU、主板、硬盘等电脑相关硬件信息。 windows提供了“wmic”&#xff08;Windows Management Instrumentation&#xff0c;Windows管理工具&#xff09;&#xff0c;提供了从命令行接口和批命令脚本执行系统管理的支持。可以打…

基于多个openEuler物理机执行mugen测试脚本

【原文链接】基于多个openEuler物理机执行mugen测试脚本 mugen脚本中有的脚本执行需要使用多个物理机&#xff0c;针对此场景&#xff0c;这里以需要两个物理机为例&#xff08;用openEuler虚拟机模拟物理机&#xff09; &#xff08;1&#xff09;首先安装两台openEuler虚拟…

【C++】C++基础知识(一)---基本概念

C基础知识&#xff08;一&#xff09;1. 输出“HelloWorld!”2. 添加注释3. 关键字4. 标识符5. 变量6. 常量1. 输出“HelloWorld!” 在visual studio中输出“HelloWorld!”。代码实现如下&#xff1a; #include <iostream> using namespace std;int main() {cout <&…

unity搭建xlua和emmy_lua的debug环境

配置步骤 1 环境 1.1 vscode 安装emmy_lua 1.2 安装对应的lua版本 1.3 安装java8并配置环境 1.4 emmy_lua的github上下载emmy_lua的64位版本&#xff0c;解压放到工程目录client\Tools\EmmyLua\ 下载地址&#xff1a;https://github.com/EmmyLua/EmmyLuaDebugger/release…