小怡分享之Java的继承和多态

news2024/11/14 15:13:39

前言:

🌈✨小怡给大家分享了Java的类和对象,今天小怡给大家分享的是继承和多态。

1.继承 

1.1   为什么需要继承 

        Java中使用类对现实世界中实体来进行描述,类经过实例化之后的产物对象,则可以用来表示现实中的实体,但是现实世界错综复杂,事物之间可能会存在一些关联,那设计程序时就需要考虑,比如猫和狗:

         通过上述代码我们可以发现,猫和狗的类存在大量重复,那么能否将共性抽取呢?面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。 

1.2    继承概念 

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

          我们可以把他们的共性抽取出来,建一个Animal类,其中,Animal类称为父类/基类或者超类,Dog和Cat称为Animal的子类/派生类。继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。 

1.3   继承的语法 

          在Java中如果要表示类之间的继承关系,需要借助extends关键字: 

 修饰符  class  子类  extends  父类{

            //...

           对上面的场景重新设计一下: 

   

注意:

1.子类会将父类中的成员变量或者成员方法继承到子类中了;

2.子类继承到父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了。 

1.4   父类成员访问 

1.4.1   子类中访问父类的成员变量

1. 子类和父类不存在同名成员变量
public class Base{
    int a;
    int b;
}
public class Derived extends Base{
    int c;

public void method(){
    a=10;//访问父类的a
    b=20;//访问父类的b
    c=30;//访问子类自己的c
   }
}
2. 子类和父类成员变量同名 
public class Base{
    int a;
    int b;
    int c;
}
public class Derived extends Base{
    int a;
    char b;

    public void method(){
        a=100;
        b=101;
        c=102;
   }
}

            大原则:就近原则。成员变量访问遵循就近原则,自己优先自己的,没有就向父类中找。

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

  • 如果访问的成员变量子类中有,优先访问自己的成员变量;
  • 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错;
  • 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。

1.4.2   子类中访问父类的成员方法 

1.成员方法名字不同 
public class Base{
     public void methodA(){
        System.out println("Base中的methodA()");
     }
}
public class Derived extends Base{
   public void methodB(){
       System.out.println("Derived中的methodB()");
   }
 
  public void methodC(){
      methodB();
      methodA();
  }
}

总结:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中没有则报错。

2.成员方法名字相同 

public class Base {
    int a;
    int b;
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
    public void methodB(){
        System.out.println("Base中的methodB()");
    }
}
public class Derived extends Base {
   int a;
   char b;
   public void methodA(int a){
       System.out.println("Derived中的method(int)");
   }
    public void methodB(){
        System.out.println("Derived中的methodB()");
    }
public void methodC(){
    methodA();
    methodA(20);
    methodB();
  }
}

[说明]

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

1.5   super关键字 

         Java提供了super关键字,主要作用:在子类方法中访问父类的成员

            super 只能指代当前类的父类,不能指代父类的父类,甚至继续向上指代。当没有提供任何的构造方法的时候,Java中会提供目前屏蔽起来的代码。但只要你写了任何已给构造方法,都不会给你自动提供。 

【注意事项】

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

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

        

1.6  子类构造方法

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

public class Base{
   public Base(){
      System.out.println("Base()");
   }
}
public class Derived extends Bae{
   public Derived(){
      System.out.println("Derived()");
   }
}
public class Test{
   public static void main(String[] args){
       Derived d=new Derived();
   }
}

        在子类构造方法中并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法,因为:子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分。父子父子肯定是先有父再有子,所以在构造子类对象的时候,先调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整。 

        注意:

1.若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法;

2.如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败;

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

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

1.7  super和this 

    【相同点】

1.都是Java中的关键字;

2.只能在类的非静态方法中使用,用来访问非静态成员方法和字段;

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

【不同点】

1.this当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象从父类继承下来部分成员的引用

2.在非静态成员方法中,this用来访问本类的方法和属性super用来访问父类继承下来的方法和属性

3.在构造方法中:this()用于调用本类构造方法,super()用于调用父类构造方法,两种调用不能同时在构造方法中出现

4.构造方法中一定会存在super()的调用,用户没有写编译器也会增加,但是this()用户不写则没有。

1.8  再谈初始化

        在没有继承关系时的执行顺序:

    1.静态代码块先执行,且只执行一次,在类加载阶段执行。

    2.当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行。

     有继承关系时的执行顺序:

    先执行父类和子类的静态代码块,再执行父类的实例和构造代码块,最后执行子类的实例和构造代码块。 

1.9  final关键字 

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

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

final int a=10;

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

final public class Animal{
    ...
}

 3.修饰方法表示该方法不能被重写(后续介绍)

1.10   继承与组合 

      和继承类似,组合也是一种表达类之间关系的方式,也是能够达到代码重用的效果。组合并没有涉及到特殊的语法,仅仅是将一个类的实例作为另一个类的字段。

继承表示对象之间的关系是is-a的关系:比如:猫是动物、狗是动物;

组合表示对象之间的关系是has-a的关系:比如:汽车。

2.多态

2.1    多态的概念

       多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。总的来说:同一件事情,发生在不同对象身上,就会产生不同的结果。

2.2  多态实现条件 

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

1.必须在继承体系下;

2.子类必须要对父类中方法进行重写;

3.通过父类的引用调用重写的方法。

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

 

        a这个引用调用eat方法可能会有多种不同的表现,这种行为就称为多态。

2.3  重写 

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

【方法重写的规则】

  • 子类在重写父类的方法时,一般必须与父类方法原型一致:返回值类型  方法名 (参数列表)要完全一致;
  • 被重写的方法返回值类型可以不同,但是必须是具有父子关系的;
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为protected。
  • 父类被static、private修饰的方法、构造方法都不能被重写  ;
  • 重写的方法,可以使用  @override   注解来显式指定。有了这个注解能帮我们进行一些合法性校验。

【重写和重载的区别】

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

即:方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。 

【重写的设计规则】

        对于已经投入使用的类,尽量不要进行修改。最好的方式是:重新定义一个新的类,来重复利用其中共性的内容,并且添加或者改动新的内容。

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

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

2.4    向上转移和向下转型

2.4.1   向上转型

            向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。

           语法格式:

父类类型  对象名=new  子类类型();

    eg:Animal animal=new Cat(“元宝”,2);

    animal是父类类型,但可以引用一个子类对象,因为是从小范围向大范围的转换。

【使用场景】

1.直接赋值;

2.方法传参;

3.方法返回。

         需要注意的是,通过父类的引用,调用子类特有的方法是无法直接调用的,这里只能调用父类自己的,这也是向上转型的缺点。 

【优缺点】

优点:让代码实现更简单灵活;

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

 

2.4.2   向下转型 

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

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

if(animal instanceof Cat){
    ...
}

 

2.5  多态的优缺点

【好处】

1.能够降低代码的圈复杂度,避免使用大量的if-else

圈复杂度:是一种描述一段代码复杂程度的方式。一段代码如果平铺直叙,那么久比较简单容易理解。而如果有很多的条件分支或者循环语句,就认为理解起来更复杂。因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数,这个个数就称为“圈复杂度”,如果一个方法的圈复杂度太高,就需要考虑重构。

2.可扩展能力更强。

【缺陷】

      代码运行效率降低

1.属性没有多态性,当父类和子类都有同名属性的时候,通过父类引用,只能引用父亲自己的成员属性;

2.构造方法没有多态性

 

🌈✨今天的分享就到这里啦,小怡和大家一起分享一起进步一起学习,“理想是指路明灯。没有理想,就没有坚定的方向;而没有方向,就没有生活”。

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

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

相关文章

无人机之环境监测篇

无人机在各个领域的应用越来越广泛,环境监测便是其中之一,它们能够提供高效、安全、经济的监测手段,帮助科学家和管理者更好的理解环境状况并采取相应措施。 一、污染监测 无人机可以搭载各种传感器,如气体检测器、红外热像仪等&…

Map遍历 32

package Array.collection;import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.function.BiConsumer;public class map1 {public static void main(String[] args) {Map<String, Double> anew HashMap<>();a.put("合法…

图论进阶之路-最短路(Floyd)

时间复杂度&#xff1a;O(n^3) 使用场景&#xff1a;当需要得知任意两个点的最短距离以及其路径时使用 准备&#xff1a;需要两个矩阵 一个记录最短距离&#xff08;D&#xff09; 一个记录最短路径的最后一个结点&#xff08;P&#xff09; 其核心在于不断的判断越过中间…

transformer代码学习及pytorch函数学习

torch.randint(low, high, size, dtypetorch.int64, devicecpu, **kwargs) low 和 high 如上所述。size 是一个元组&#xff0c;表示张量的形状。dtype 是数据类型&#xff0c;默认为 torch.int64&#xff0c;表示生成的整数是64位整数。device 指定了生成张量所在的设备&#…

结构体与共用体

一、链表 1.尾插 2.头删&#xff1a; 3.尾删&#xff1a; 4.内存泄漏&#xff1a;malloc调用的节点需要手动清除 头删效率更高&#xff0c;算法复杂度更低 二、共用体 1.形式&#xff1a;union 共用体名{成员表列} 变量表列&#xff1b;共用体的成员会占用同样的内存空间 …

微信小程序_对接腾讯实时音视频_多人会议

目录 一、开通腾讯实时音视频 1.腾讯实时音视频简介 2.创建应用 二、快速接入 1.微信小程序账号类目资格 2.跑通腾讯多人会议源码 3.发行项目 三、开发自己的业务代码 如何对接腾讯实时音视频的多人会议产品&#xff0c;从开通服务到对接完成&#xff0c;一 一讲解。 一…

LBS 开发微课堂|Polyline绘制优化:效果更丰富,性能更佳!

为了让广大的开发者 更深入地了解 百度地图开放平台的技术能力 轻松掌握满满的技术干货 更加简单地接入 开放平台的服务 我们特别推出了 “位置服务&#xff08;LBS&#xff09;开发微课堂” 系列技术案例 第一期的主题是 《Polyline 绘制优化升级》 你还想了解哪些…

MySQL:Prepared Statement 预处理语句

预处理语句&#xff08;Prepared Statement&#xff09; 是一种在数据库管理系统中使用的编程概念&#xff0c;用于执行对数据库进行操作的 SQL 语句。 使用预处理语句的具体方式和语法依赖于所用的编程语言和数据库管理系统。常见的编程语言如 Java、PHP、Python 和 C# 都提供…

如何把视频语音转文字?交给这4款工具就完事

这两天巴黎奥运会的盛大开幕&#xff0c;世界各地的记者们纷纷涌入这个体育盛事的现场&#xff0c;带着他们的镜头和麦克风&#xff0c;捕捉每一个激动人心的瞬间。 然而&#xff0c;随着采访的深入&#xff0c;如何快速准确地将这些珍贵的视频内容转化为文字记录&#xff0c;…

代码随想录算法训练营第十七天 | 654.最大二叉树, 617.合并二叉树 ,700.二叉搜索树中的搜索 , 98.验证二叉搜索树

目录 654.最大二叉树 思路 方法一&#xff1a; 递归基础版 方法二&#xff1a;递归使用下标 方法三&#xff1a;递归使用切片 心得收获 617.合并二叉树 思路 递归法 迭代法 方法一&#xff1a; 递归 - 前序 - 修改root1 方法二&#xff1a;递归 - 前序 - 新建root…

敦煌文化主题页面 HTML,CSS,Javascript 源码分享

使用技术&#xff1a;HTML&#xff0c;CSS&#xff0c;JavaScript 项目亮点&#xff1a;加入了大量的CSS动画效果&#xff0c;以及JS交互效果&#xff0c;水平适合初学者以及大学生&#xff0c;包含登录注册页 需要的可以dd&#xff0c; 绿泡泡&#xff1a;ColdDayOne

AI入门指南:什么是人工智能、机器学习、神经网络、深度学习?

文章目录 一、前言二、人工智能(AI)是什么&#xff1f;起源概念人工智能分类人工智能应用 三、机器学习是什么&#xff1f;概念机器学习常见算法机器学习分类机器学习与人工智能的关系 四、神经网络是什么&#xff1f;概念神经网络组成部分神经网络模型神经网络和机器学习的关系…

【Hot100】LeetCode—76. 最小覆盖子串

题目 原题链接&#xff1a;76. 最小覆盖子串 1- 思路 利用两个哈希表解决分为 &#xff1a;① 初始化哈希表、②遍历 s&#xff0c;处理当前元素&#xff0c;判断当前字符是否有效、③收缩窗口、④更新最小覆盖子串 2- 实现 ⭐76. 最小覆盖子串——题解思路 class Solution …

Python | Leetcode Python题解之第316题去除重复字母

题目&#xff1a; 题解&#xff1a; class Solution:def removeDuplicateLetters(self, s: str) -> str:vis defaultdict(int)cnt defaultdict(int)for ch in s: cnt[ch] 1queue []for ch in s:if vis[ch] 0:while queue and queue[-1] > ch and cnt[queue[-1]]:vi…

VS Code设置C++编译器路径

C_Cpp.default.compilerPath是C/C编译器路径; python.condaPath是conda路径.

Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝,无法连接

目录 报错 解决办法 报错 在redis文件夹的路径栏中输入 cmd 命令&#xff0c;打开控制栏窗口界面 报错说是 redis-cli.exe打开就显示Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝&#xff0c;无法连接。 解决办法 &#xff08;1&#xff09;cmd…

【教学类-71-01】20240802蔬菜切切乐01

背景需求&#xff1a; ✂️自制教具分享✂️蔬菜切切乐&#xff08;剪纸&#xff09; - 小红书 (xiaohongshu.com)https://www.xiaohongshu.com/explore/65bf6809000000001100fa53?app_platformandroid&ignoreEngagetrue&app_version8.46.0&share_from_user_hidd…

mybatis保存postgresql数组格式数据

新建表的时候在int4后加上[]中括号就行 -- 创建数组 SELECT ARRAY[1, 2, 3, 4, 5];-- 访问数组元素&#xff08;从1开始&#xff09; SELECT ARRAY[1, 2, 3, 4, 5][1]; -- 返回 1-- 数组长度 SELECT array_length(ARRAY[1, 2, 3, 4, 5], 1); -- 返回 5-- 数组连接 SELECT ARRA…

C语言 | Leetcode C语言题解之第316题去除重复字母

题目&#xff1a; 题解&#xff1a; char* removeDuplicateLetters(char* s) {int vis[26], num[26];memset(vis, 0, sizeof(vis));memset(num, 0, sizeof(num));int n strlen(s);for (int i 0; i < n; i) {num[s[i] - a];}char* stk malloc(sizeof(char) * 27);int stk…

Linux软件编程

8月1日学习了最后的标准IO&#xff0c;流的偏移。然后进入了文件IO的学习&#xff0c;包括文件的打开、读写、关闭以及偏移。之后又学习了剩余的一些函数接口&#xff0c;可以对文件进行一些其余操作。 8月2日学习了目录文件和链接文件的操作。目录文件的操作包括目录的创建、…