当前位置: 首页 > article >正文

JAVA继承和多态

一.继承:

     1.super关键字访问父类变量:

        在我们写代码过程中,如果两个类或者多个类有重复的相同变量和方法,那么我们可以使用继承来优化代码,达到了代码的复用效果。

        比如诸多类中的其中一个 Test 子类继承 Base 这个父类:

        有下面代码:        

        

         可以看到,想要子类继承父类,要在后面加上 extends ,再加上父类类名

        父类有两个变量 a , b ,子类有变量a ,c ,

        他们在堆里存储时这样的:

        

        那么在子类中访问变量 a, b c, 会怎么样呢?

        可以看到,打印结果是 10,2 ,3

        注意:

        1.当访问的变量名 是 父类成员名 与 子类成员名 有重名的, 优先访问子类成员的

        2.当 访问的变量名 父类没有,子类有,则访问子类的。

        3.当 访问的变量名 父类有,子类没有,则访问父类的。

        4.当 访问的变量名 父类没有,子类没有,则编译出错。

        那么,当访问的变量名 是 父类成员名 与 子类成员名 有重名的时候,想要访问父类的,该怎么办?

        需要用到关键字: super

        先看一张图:

        

         再看代码:

        

        运行结果:

        

        可以看到,当访问的变量名 是 父类成员名 与 子类成员名 有重名的时候,可以通过 super.父类成员名  获取父类成员,这是父类特有的。

        this 则可以获取 子类和父类的,当父类成员名 与 子类成员名 有重名的时候,this获取的是子类的。

        当父类成员名 与 子类成员名 有重名的时候,默认不加 super或者 this 也是访问子类。

        当父类有的,子类没有的,用 super 也可以访问父类的。

        总结:

        super 是访问父类特有的,能使代码更易懂,让人知道 当前的变量是来自子类 的还是父类的。

        2. super 关键字访问父类方法:

先看一段代码:

        

        打印结果:

         

         从两个分隔符中间的打印结果可以知道,supre 关键字在 父类与子类 同名的方法 时的用法时一样的, super 代表访问父类的方法。如果都有就访问子类的。

        但是,注意:

        

         这三个方法的关系分别标出来了,可以看到,左边的重载 是不同类 的两个方法,所以,继承关系上也可以重载。

        注意:

        1. super 只能在非静态方法中使用。

        2. 在子类方法中, super 用来访问父类的成员变量和方法。

        上面的重写在多态会讲到。

        

        3.子类构造方法:

        当子类继承了父类后,应该怎么初始化成员呢?

        先看代码:

        

        

         首先,初始化子类成员之前(这没写子类的成员,为了演示操作),要先对父类的成员进行初始化,可以看到,中间的 Dog 类初始化前,里面 利用 super 关键字 对父类成员传参过去初始化了,走完父类初始化后,回到 Dog 类,子类初始化也完成了。

        注意:

        1.如果不先初始化父类成员,编译时会报错。

        2.如果父类和子类都没写构造方法,那么编译器就会有个默认的初始化:

        

        默认的初始化他什么都没做。但是,当 Dog 类里面要传参到Animal类 初始化, 父类就要写有传参数的初始化,不然会报错。

        比如这个就报错了:

        

        注意:

        1.在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句

        2. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现。

        super 与 this 相同点:

        1.super 和 this 只能在类的非静态方法中使用,用来访问非静态成员方法和字段。

        2. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在

        

        继承关系后代码块:

        先看代码:

        

        执行结果:

        

        可以看到,继承关系的父类和子类执行顺序是:

        父类静态代码块 ---> 子类静态代码块 ---> 父类实例代码块 ---> 父类构造方法 --->  子类实例代码块 ---> 子类构造方法

        

        4.final 修饰

        比如这段代码:

        

         我们不想让 manman 这个类继续继承 Dog 类怎么办?

        上图是在 Dog 类前加了 final 修饰了,代表当前类不能被继承

        

        5.继承方式:

        Java中只支持以下几种继承方式:

        

         

        

        二.多态:

        1.向上转型:

        父类引用 引用子类对象

            向上转型有三种方式:

        在本次例子中,Animal 是父类,Dog是子类

        (1)直接赋值:

        

        (2)利用参数传递:

        

        这里利用了一个test方法,把 Dog 类型的 dog引用 利用传参方式,赋值成了父类的 引用。

        (3)返回值传递:

        

        

         方法里引用了一个子类对象,接着返回类型是 父类的Animal 类型了。

        

        

        2.重写:

        什么是重写?

        两个方法:

        1.方法名相同

        2.参数列表相同【参数个数,数据类型,顺序】。

        3.返回值相同

        那么,看下面代码:

        

         animal 引用可以访问 Animal 的 eat 方法,但是不能调用子类的dark方法(animal.dark();)(图片没展示dark的方法,但是子类有dark方法),而父类没有dark这个方法,因为向上转型不能调用到子类特有的方法,那么,如果对 eat 方法重写呢?也就是给 Dog 写个 eat方法。

        代码:

        

         运行结果:

        

        结果是打印了 Dog 类里重写的 eat 方法。 

        通过 animal 这个引用,只能调用Animal自己的成员,但是,当子类重写父类的方法之后,animal可以调用子类重写的方法。

      这一步也叫动态绑定

        动态绑定条件:

        1.父类引用 必须引用子类对象。

        2.子类重写了父类的方法,通过父类引用调用这个被重写的方法。

        

        

        那么什么是静态绑定呢?

        例如:

        

        这种编译的时候,根据方法的参数个数,类型等等,就能确定调用哪个方法。这就叫做静态绑定。

        关于重写的注意事项:

        1.父类的方法如果是被 static 修饰的,则子类不能重写该方法。

        2.父类的方法如果是被 final 修饰的,则子类不能重写该方法。

        3.父类的方法如果是被 private 修饰的,则子类不能重写该方法。

        4.子类重写父类的方法的时候,子类方法的访问权限要  大于或等于  父类的访问权限。

        比如:

        

         

        运行结果:

        

        因为 子类 protected 大于 父类 默认的 default权限。而且都是包访问权限。

        

        

        重写有一种特殊情况:

        

         

        他们的返回值此时构成父子类关系也是重写

        

        3.向下转型:

        比如这段代码:

        

        

        我又定义了个 Bird 类 在 Test类 中先使用 Animal 类型的引用 animal 引用 Bird 对象,再发生向下转型,通过强制类型转换成 Bird 类型的引用。 第二步的过程就叫做向下转型。

        

        向下转型是不安全的,比如:

        

         编译出错了:

        

         这是类型转换异常。那么怎么样才能编译成功呢?

        这样:

        

         

        可以用该条件(animal instanceof Bird )来判断。 

        

        

      4.多态例子:

        比如我们要打印两个图形:

        代码:

        

                打印结果:

        

         可以看到,各自的子类都与父类有draw 方法重写,那么,当我在 Test 类里 把不同的子类对象 给到 父类引用后,会根据 重写方法来实现。

       

        

        特殊例子:

        有这么一段代码:

        

        运行结果是:

        D.func() 0

        

        

        为什么呢?

        在这里由于没有静态的,代码块的执行顺序:

        父类的实例---》父类的构造---》子类的实例---》子类的构造。

        

        首先,当执行 D d = new D()后,会去调用构造方法,由于D类里代码里没写构造方法,编译器默认会有个构造方法,去到了父类 B 的构造方法里,调用了func();接着由于func方法子类父类重写了,会去到子类的func方法里,打印了结果,但是父类构造方法还没结束,而num作为子类的实例成员,没执行到 子类的实例 就打印了基本类型0的结果。

        


http://www.kler.cn/news/361068.html

相关文章:

  • 18.VScode写Java项目的教程
  • 使用ETL进行数据接入的方式
  • 深入探索LINUX中AWK命令:强大的文本处理工具
  • 后端常用安全措施
  • idea中,git提交时忽略某些本地修改.将文件从git暂存区移除
  • 使用GraphRAG系统实现本地部署的Ollama模型问答系统
  • 实现鼠标经过某个元素时弹出提示框(通常称为“工具提示”或“悬浮提示”)
  • 虚拟培训引领潮流:首个电力调度元宇宙标准获批立项
  • 大数据干了什么?
  • 【D3.js in Action 3 精译_035】4.1 D3 中的坐标轴的创建(下篇):坐标轴与轴标签的具体实现
  • 【Go进阶】协程的创建以及通信
  • 我是类(最终版)
  • Java | Leetcode Java题解之第491题非递减子序列
  • 在windows上开发的python程序能直接在linux上跑吗?
  • echarts柱状图数据太多,如何实现鼠标滑动查看
  • 【五】企业级JavaScript开发之入门
  • Android 原生程序使用gdb, addr2line, readelf调试
  • CTFHUB技能树之XSS——DOM反射
  • JMeter详细介绍和相关概念
  • LLM----BERT+HuggingFace理论及基础入门实战