【JavaSE】面向对象---多态

news2024/11/28 10:49:53

前言

  1. 本篇以Java初学者视角写下,难免有不足,或者术语不严谨之处。如有错误,欢迎评论区指正。
  2. 本篇说明多态相关的知识。
  3. 若本文无法解决您的问题,可以去最下方的参考文献出,找出想要的答案。

在这里插入图片描述

多态概念

多态(polymorphism):多种形态,具体是不同对象完成某个行为,它们的状态不同。
比如,同样是跑1000米,有些人气喘吁吁(我),还有一些大佬跑完气都不带喘的。
我认为多态是一种思想。而要理解多态得熟悉向上转型,和方法重写的知识。
有关笔者继承的博客:可以浅读了解一下

向上转型

字面意思:转型,类型转换;向上,即子类向超类转换。
向上转型属于自动转换类型可以不用强制类型转换运算符。

public class Main {

    public static void main(String[] args) {
	Dog dog =Dog.Init("旺财",2);//这里采用的是静态工厂方法,不熟悉的可以看下面的参考文献阅读一下。
    Animal animal = dog;//这里Dog类转换成了父类Animal
    }
}

不熟悉的可以先跳过,这里只是为了代码的完整性放这儿/

//Dog.java
class Dog extends Animal{

    public static Dog Init(String name,int age){
        Dog dog = new Dog(name,age);
        return dog;
    }
    public Dog(String name,int age){
        super(name,age);
    }
    public Dog(){

    }
    @Override
    public void eat() {
        System.out.println(this.name+" 正在吃狗粮.......");
    }
}

//Animal.java
class Animal {
    String name;
    int age;

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

    }
    public static void fun(Animal animal){
        animal.eat();
    }
    public void eat(){
        System.out.println(this.name + "正在吃法。");
    }

}

在Java中,对象变量是多态的,它既可以引用自身的类型,还可以引用其子类的对象。

实现向上转型有三种方式
1.直接赋值

 Animal animal = new Dog();//直接创建一个子类对象然后赋值给超类的对象变量

2.方法传参

//Main.java
public class Main {

    public static void main(String[] args) {

        Animal.fun1(new Dog());
    }
}

//Animal.java类中有如下静态方法
public static void fun1(Animal animal){
 }

这种通过调用超类的方法传子类的实参来达到向上转型的效果。

3.返回值

//Animal.java中有如下静态方法。
//函数内部实例化子类对象,然后由于返回值要与类型匹配,自动地发生向上转型。
public static Animal fun2(){
        Dog dog = new Dog();
        return dog;
    }

动态绑定

这里说明动态绑定,但涉及到方法重写(先忽略这个问题)。
以下是三个类,两个子类一个超类,重点关注每个类中的eat方法.

//Dog.java
class Dog extends Animal{

    public static Dog Init(String name,int age){
        Dog dog = new Dog(name,age);
        return dog;
    }
    public Dog(String name,int age){
        super(name,age);
    }

    //关注eat方法
    @Override
    public void eat() {
        System.out.println(this.name+" 正在吃狗粮.......");
    }
}

//Animal.java
class Animal {
    String name;
    int age;

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

    public static void fun(Animal animal){
        animal.eat();
    }
    //关注eat方法
    public void eat(){
        System.out.println(this.name + "正在吃饭。");
    }

}

//Bird.java
class Bird extends Animal{
    public static Bird Init(String name,int age){
        Bird bird = new Bird(name,age) ;
        return bird;
    }

    public Bird(String name,int age){
        super(name,age);
    }
    //关注eat方法
    @Override
    //eren jeger
    public void eat() {
        System.out.println(this.name+" 正在吃虫子.......");
    }
}

🆗接下来来分析Main类了

public class Main {

    public static void main(String[] args) {
        Animal animal= Dog.Init("kunkun",1);
        animal.eat();//这里的eat调用的是哪个类里面eat方法?
    }
}

在这里插入图片描述

调用的是子类Dog,为什么呢?这里不是向上转型成Animal(超类)了吗?
嗯,这里就得介绍本标题的主角:动态绑定机制

  1. 动态绑定机制,简单来说,以父类为编译类型,创建子类对象的时候,绑定子类运行类型,当我们再调用方法的时候,能够有序的寻找方法,实现方法的有序调用。
  2. 解释:1.动态绑定机制在运行时调用方法绑定子类运行。
    2.程序在编译时,确实调用的时父类的eat方法。当运行代码的时候,通过父类的引用,调用了父类和子类重写的方法,结果实际调用了子类的方法,此时称这种情况为动态绑定。
    3.程序运行并且采用动态绑定调用方法时,JVM会调用父类所引用对象的实际类型的方法。

    三种解释任选理解。下面来说明方法重写。

方法重写

在上面的例子中用到方法重写,我们这里详细说说。

//Dog类中(子类)
 public void eat() {
        System.out.println(this.name+" 正在吃狗粮.......");
    }
//Bird类中(子类)
 public void eat() {
        System.out.println(this.name+" 正在吃虫子.......");
    }
//Animal类中(超类)
 public void eat(){
        System.out.println(this.name + "正在吃饭。");
    }

显而易见,Animal执行eat打印的是某某正在吃饭,而Dog打印的是某某吃狗粮。
超类的有些方法对子类并不适用,这里就是不够具体。每种动物的食物不同,这里就可以通过方法重写来针对特定的类写对应的eat方法来覆盖原先超类的方法。
没错,这就是方法重写(又称覆盖方法)。

若子类和超类的方法满足以下:
1.方法名相同
2.参数相同(参数类型,参数个数,参数序列相同)
3.返回类型相同
则构成方法重写。

方法重写的注意事项:

1.若方法前面有private static final 修饰,或者其本身是构造器(构造方法),编译器本身可以确定应该调用哪些方法。这些方法不能重写。
2.方法重写时,子类的访问权限一定大于等于超类的访问权限。若超类是public,则子类也必须是public类,不能protected等等。
3.子类和超类的覆盖方法返回类型可以不同,但必须构成父子关系。
`

//Animal类一部分
 public Animal eat(){
        System.out.println(this.name + "正在吃饭。");
        return null;
    }
    //Dog类一部分
 public Dog eat() {
        System.out.println(this.name+" 正在吃狗粮.......");
        return null;
    }
}

重写与重载区别

重写与重载都是一种多态。
方法重载是类之间的多态。方法重写是子类与超类的多态。

方法重载:
方法之间同名,但参数列表必须修改。
返回类型,访问修饰符随意。

方法重写:
1.方法名必须相同
2.参数相同(参数类型,参数个数,参数序列相同)
3.返回类型相同(构成父子关系可以不同)
4.访问修饰符必须满足子类权限大于等于超类。

下面是补充部分:

补充

向下转型

向下转型有风险。向下转型是超类强制转换成子类。这里必须借助强制转换运算符。
系统来说:将一个超类类型的引用变量强制转换成子类的过程叫做向下转型。
但不是所有对象都能向下转型,只要当这个对象原本就是子类向上转型过来时才能向下转型。
???啥意思呢?
举例

public class Main {

    public static void main(String[] args) {
        Animal animal= new Animal("kunkun",1);//直接new一个超类对象向下转型
        Dog dog =(Dog)animal;
        dog.eat();//结果如何呢?打印Dog的eat还是Animal的eat呢?

    }
}

结果是都不打印,直接报错。
在这里插入图片描述

//本来是狗,还原成狗,可以。
public class Main {

    public static void main(String[] args) {
        Animal animal= Dog.Init("kunkun",2);
        Dog dog =(Dog)animal;
        dog.eat();

    }
}

```java
//本来是狗,还原成鸟不合理。你家狗会飞???
public class Main {

    public static void main(String[] args) {
        Animal animal= Dog.Init("kunkun",2);
        Bird bird =(Bird)animal;
        bird.fly();

    }
}

在这里插入图片描述


> 总结:
> 向下转型唯一正确的使用用法:
> 1.先向上转型,让父类引用子类对象。
> 2.向下转型类型要与最初子类类型相同。别从一个子类转换成另一个子类了。报错警告!

##  instanceof关键字
**instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。**
[instanceof关键字详解](http://t.csdnimg.cn/IIZbD)
```java
public class Main {

    public static void main(String[] args) {
        Animal animal= Bird.Init("kunkun",2);
        Bird bird =(Bird)animal;
        if( bird instanceof Bird)
        {
            bird.fly();
        }else{
            System.out.println(false);
        }

    }
}

静态绑定

其实前面提过:若方法前面有private static final 修饰,构造器(构造方法),编译器本身可以确定在那个类调用这些方法。
像上述在这种程序执行前就已经绑定了方法在那个类中调用的方法称为静态绑定。

避免在构造方法中使用重写

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

看main方法,首先实例化D类对象,先进入D中构造方法,构造方法为默认构造方法,由于继承关系,子类构造还有里面还要调用父类构造方法。父类构造方法里的调用func()即子类和父类方法重写,由于动态绑定,会调用子类的func(),而此时子类的num还没初始化为1,默认为0.所以最终打印结果为 D.func() 0
在这里插入图片描述

总之,构造器中最后不要调用实例化的方法,调用静态绑定的方法比如final,private修饰的方法。因为,若实例方法被子类重写,那么就动态绑定了,会调用子类的方法。

参考文献

  • Instance关键字详解
  • 静态绑定与动态绑定
  • 重载与重写—强烈建议看此篇
  • 向上转型与向下转型
  • 类加载顺序
    愿此行,终抵群星。

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

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

相关文章

【Ardiuno】实验使用ESP32连接Wifi(图文)

ESP32最为精华和有特色的地方当然是wifi连接,这里我们就写程序实验一下适使用ESP32主板连接wifi,为了简化实验我们这里只做了连接部分,其他实验在后续再继续。 由于本实验只要在串口监视器中查看结果状态即可,因此电路板上无需连…

最短路径——迪杰斯特拉与弗洛伊德算法

一.迪杰斯特拉算法 首先对于最短路径来说:从vi-vj的最短路径,不用非要经过所有的顶点,只需要找到路径最短的路径即可; 那么迪杰斯特拉的算法:其实也就与最小生成树的思想类似,找到较小的,然后…

在网上赚钱,可以自由掌控时间,灵活的兼职副业选择

朋友们看着周围的人在网上赚钱,自己也会为之心动,随着电子设备的普及,带动了很多的工作、创业以及兼职副业选择的机会,作为普通人的我们,如果厌倦了世俗的朝九晚五,想着改变一下自己的生活,可以…

STM32 printf 重定向到CAN

最近在调试一款电机驱动板 使用的是CAN总线而且板子上只有一个CAN 想移植Easylogger到上面试试easylogger的效果&#xff0c;先实现pritnf的重定向功能来打印输出 只需要添加以下代码即可实现 代码 #include <stdarg.h> uint8_t FDCAN_UserTxBuffer[512]; void FDCAN_p…

btstack协议栈实战篇--Hello World example

btstack协议栈---总目录-CSDN博客 目录 1.定时计时器设置 2.主要应用程序设置 3.运行log如下图 该示例演示了如何提供周期性定时器来切换LED并将调试消息作为最小BTstack测试发送到控制台。 1.定时计时器设置 由于BTstack中的计时器是单触发的&#xff0c;因此通过在心跳中重新…

从0到1:企业办公审批小程序开发笔记

可行性分析 企业办公审批小程序&#xff0c;适合各大公司&#xff0c;企业&#xff0c;机关部门办公审批流程&#xff0c;适用于请假审批&#xff0c;报销审批&#xff0c;外出审批&#xff0c;合同审批&#xff0c;采购审批&#xff0c;入职审批&#xff0c;其他审批等规划化…

Android Qt开发环境部署

我总结了在Qt中搭建Android开发两个要点&#xff1a; 1.JDK一定要是JDK1.8的 2.要下载目标Android版本的SDK&#xff0c;可以在Android studio SDK查看对应Android SDK版本 下面我们开发搭建。首先需要JDK&#xff0c;链接如下&#xff1a;链接&#xff1a;https://pan.baidu.…

★pwn 24.04环境搭建保姆级教程★

★pwn 24.04环境搭建保姆级教程★ &#x1f338;前言&#x1f33a;Ubuntu 24.04虚拟机&#x1f337;VM&#x1f337;Ubuntu 24.04镜像 &#x1f33a;工具&#x1f337;可能出现的git clone错误&#x1f337;复制粘贴问题&#x1f337;攻击&#x1f337;编题 &#x1f33a;美化&…

【CS.DB】从零到精通:这可能是全网最全面最强大的SQL入门教程

文章目录 1. 什么是SQL&#xff1f;1.1 SQL的历史1.1.1 SQL的标准化过程 2. SQL基础语法2.1 数据库操作2.1.1 创建数据库2.1.2 删除数据库 2.2 表操作2.2.1 创建表2.2.2 删除表2.2.3 修改表 2.3 数据操作2.3.1 插入数据2.3.2 更新数据2.3.3 删除数据 2.4 查询数据2.4.1 基本查询…

【Linux】进程4——进程状态

1.进程状态 什么是状态&#xff1f; 每个人都有状态——颓废&#xff0c;阳光&#xff0c;积极向上。。。。 进程也有状态 在操作系统中&#xff0c;由于进程的数量是非常多的&#xff0c;而系统的资源又非常少&#xff0c;所以不可能每一个进程在每时每刻都会处于上处理机运…

【 技术栈】技术方案到底怎么写?

文章目录 一、背景二、技术方案重要性三、常见的技术方案有哪些内容1、系统用例2、功能整体链路2.1、核心业务流程 3、数据库设计4、接口设计5、非功能设计5.1、性能与稳定性5.2、监控 7、系统风险点评估 四、总结 一、背景 工作中&#xff0c;有一些需求或者技术改造&#xf…

计算机网络--应用层

计算机网络–计算机网络概念 计算机网络–物理层 计算机网络–数据链路层 计算机网络–网络层 计算机网络–传输层 计算机网络–应用层 1. 概述 因为不同的网络应用之间需要有一个确定的通信规则。 1.1 两种常用的网络应用模型 1.1.1 客户/服务器模型&#xff08;Client/Se…

Java面试八股之什么是反射,实现原理是什么

Java中什么是反射&#xff0c;实现原理是什么 Java中的反射&#xff08;Reflection&#xff09;是一种强大的特性&#xff0c;它允许程序在运行时检查和操作类、接口、字段和方法的信息。简而言之&#xff0c;反射机制使得程序能够在运行时动态地了解和使用自身或其他程序集中…

python文件:py,ipynb, pyi, pyc, pyd, pyo都是什么文件?

1、Python文件类型介绍 &#x1f4c1; 1.1 .py 文件&#xff1a;源代码基础 .py 文件是 Python 最基本的源代码文件格式&#xff0c;用于存储纯文本形式的 Python 代码。它是开发者编写程序的主要场所&#xff0c;包含函数、类、变量定义以及执行逻辑。Python 解释器直接读取…

【排序算法】总结篇

✨✨这些 排序算法都是指的 需要进行比较的排序算法 ✨✨下面都是略微讲解一下思路&#xff0c;如果需要详细了解哪一个排序&#xff0c;点击&#x1f449;链接即可 ✨✨对于时间、空间复杂度、稳定性&#xff0c;希望你&#x1f9d1;‍&#x1f393;能够理解记忆&#x1f9d1;…

MyBatisPlus插件生成代码

文章目录 概要安装插件使用插件 概要 MyBatis-Plus 是 MyBatis 的增强工具&#xff0c;旨在简化 MyBatis 的开发。MyBatis-Plus 代码生成器插件可以自动生成项目中常见的代码&#xff0c;如实体类、Mapper 接口、Service 接口和实现类、Controller 等&#xff0c;从而减少手动…

python代码中参数的默认值

python中的函数&#xff0c;可以给形参指定默认值。 带有默认值的参数&#xff0c;可以在调用的时候不传参。 如上图所示&#xff0c;在给函数设定形参的时候可以给函数形参设定默认值&#xff0c;当然默认参数的形参应该在非默认形参的后面。 如果在调用函数的时候&#xff…

SpringBoot整合SpringSecurit(二)通过token进行访问

在文章&#xff1a;SpringBoot整合SpringSecurit&#xff08;一&#xff09;实现ajax的登录、退出、权限校验-CSDN博客 里面&#xff0c;使用的session的方式进行保存用户信息的&#xff0c;这一篇文章就是使用token的方式。 在其上进行的改造&#xff0c;可以先看SpringBoot…

ctfshow-web入门-命令执行(web41_exp与分析)

过滤不严&#xff0c;命令执行 preg_match(/[0-9]|[a-z]|\^|\|\~|\$|\[|\]|\{|\}|\&|\-/i, $c) 过滤掉了数字、字母以及一些符号&#xff0c;之前接触过的无字母 rce 是取反编码再取反&#xff0c;采用不可见字符去绕过正则&#xff0c;但是这里取反符号被过滤掉了&#x…

还在为线上BUG苦苦找寻?试试IntelliJ IDEA远程调试线上Java程序

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…