【JavaSE】多态、抽象类

news2025/7/11 12:30:20

文章目录

  • 1. 向上转型
  • 2. 重写
  • 3. 多态
  • 4. 向下转型
  • 5. 抽象类

1. 向上转型

我们来看看以下程序

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println("父类的方法");
    }
}
class Cat extends Animal {
    public String hire;
    public void mew() {
        System.out.println(this.name + ":喵喵");
    }
    public Cat() {
        super();
        System.out.println("子类构造方法");
    }
}

public class Test1 {
    public static void main(String[] args) {
        Animal animal = new Cat();//通过父类引用 引用子类对象
        animal.name = "凉凉";
        animal.age = 3;
        animal.eat();
    }
}

通过以上程序我们可以看到在实例化对象时,通过父类引用 引用子类进行实例化对象。
所以向上转型就是:父类引用 引用子类对象。


注意:

  1. 发生向上转型时,父类对象 animal 只能访问自己特有的属性和方法,不能访问子类的成员变量和成员方法,当访问子类成员时将会报错。 在这里插入图片描述

  2. 发生向上转型时,子类的构造方法也会被调用。我们执行一下上面的程序。 在这里插入图片描述



2. 重写

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(this.name + "正在吃饭");
    }
}
class Cat extends Animal {
    public String hire;
    public void mew() {
        System.out.println(this.name + ":喵喵");
    }
    public void eat() {
        System.out.println(this.name+ "正在吃猫粮");
    }
}
public class Test1 {
    public static void main(String[] args) {
        Animal animal = new Cat();//向上转型
        animal.name = "凉凉";
        animal.eat();
    }
}

当我们运行上面代码看看结果是什么。
在这里插入图片描述

这时我们就有疑惑了,发生向上转型时父类引用不是不能访问子类的成员方法吗,这里为什么是访问子类的成员方法呢?

这时因为发生了动态绑定,子类重写了 eat() 方法,此时用的是子类的 eat() 方法。

  1. 先来分析编译阶段:
    对于编译器来说,编译器只知道 animal 的类型是Animal,所以编译器在检查语法的时候,会去Animal.class字节码文件中找eat()方法,找到了,绑定上 eat() 方法,编译通过,静态绑定成功。(编译阶段属于静态绑定)

  2. 再来分析运行阶段:
    运行阶段的时候,实际上在堆内存中创建的 java 对象是 Cat 对象,所以当我们子类重写了 eat() 的时候,真正参与 eat() 的对象是Cat,所以运行阶段会动态执行 Cat 对象的 eat() 方法。这个过程属于运行阶段绑定。(运行阶段绑定属于动态绑定)

1. 总的来说就说编译时还是 Animal 的 eat() 方法,但是运行时变为子类的 eat() 方法,这叫运行时绑定,也叫动态绑定。

2. 当发生向上转型时,看子类有没有重写父类的方法,有的话则调用子类方法,没有则调用父类的。

我们可以看到在编译时还是 Animal 的 eat() 方法。
在这里插入图片描述

重写时是动态绑定
重载时是静态绑定


那么怎么样才能发生重写呢?
在这里插入图片描述

静态的方法不能发生重写

在这里插入图片描述

那有的人就会说我这么写呢:

在这里插入图片描述

重写规则:

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


3. 多态

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

  1. 必须在继承体系下。
  2. 子类必须要对父类中方法进行重写。
  3. 通过父类的引用调用重写的方法 ,即父类引用 引用子类对象,通过该对象访问重写的方法。

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

//动物类
class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println("正在吃饭");
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
//猫类
class Cat extends Animal {
    public void mew() {
        System.out.println(this.name + "喵喵叫");
    }

    public Cat(String name, int age) {
        super(name, age);
    }

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

}
//狗类
class Dog extends Animal {
    public void bark() {
        System.out.println(this.name + "汪汪叫");
    }

    public Dog(String name, int age) {
        super(name, age);
    }

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

}

public class Test1 {
    public static void main(String[] args) {
        Animal animal1 = new Cat("猫", 2);
        Animal animal2 = new Dog("狗",3);
        animal1.eat();
        animal2.eat();
    }
}

在这里插入图片描述

像这样,动物有许多,但是它们吃的东西可能是不一样的,猫吃猫粮,狗吃狗粮。Animal 类可以有多个子类,当发生向上转型时,父类引用 引用不同子类的对象时,展现出不同的行为,这就是多态的思想。

例如:上面的父类引用 分别引用 Dog 对象 和 Cat 对象,当利用这些父类引用去访问 eat() 方法时展现出不同的行为(猫吃猫粮,狗吃狗粮)。

具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态。

多态:就是一个父类可以有多个子类,多个子类中分别重写了父类的同一个方法,当不同对象(即不同子类对象)去调用这个方法时表现出不同的行为



4. 向下转型


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

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println("正在吃饭");
    }
}
//鸟类
class Bird extends Animal {
    @Override
    public void eat() {
        System.out.println(this.name + "正在吃虫子");
    }
    public void fly() {
        System.out.println(this.name + "正在飞");
    }
}
public class Test1 {
    public static void main(String[] args) {
        Animal animal = new Bird();
        Bird bird = (Bird)animal;	//向下转型
        bird.fly();	//向下转型后调用子类特有的方法
    }
}

但向下转型有时并不安全。

在这里插入图片描述如上,当我们用animal引用 引用 Cat 对象,animal 实例不是 Bird 的对象,所以运行时会报异常

在这里插入图片描述

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

在这里插入图片描述



5. 抽象类

//图形类
class Shape {

    public void draw() {
        System.out.println("画图形");
    }
}
//圆形类
class Circle extends Shape{
    @Override
    public void draw() {
        System.out.println("⚪");
    }
}
//菱形类
class Rhombus extends Shape{
    @Override
    public void draw() {
        System.out.println("◆");
    }
}
//三角形类
class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("🔺");
    }
}
public class Test1 {
    
    public static void draw(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        Shape circle = new Circle();
        Shape rhombus = new Rhombus();
        Shape triangle = new Triangle();
        draw(circle );
        draw(rhombus);
        draw(triangle);
    }
}

当我们这么写时,那么父类中的draw方法中的东西是不是多余的,那么我们可不可以不写?

在这里插入图片描述


1. 抽象类概念

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

在打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由 Shape的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个 抽像方法(abstract method), 包含抽象方法的类我们称为 抽象类(abstract class).

在这里插入图片描述

有了抽象类我们就可以由上面的父类中的方法变为下面的样子。
在这里插入图片描述

  • 被 abstract 修饰的方法叫抽象类,方法被修饰后可以不写具体的操作。当然一个类中有了抽象方法后,这个类就必须定义成一个抽象类

2. 抽象类不能进行实例化

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

3. 抽象类的成员变量和方法都是和普通类是一样的,只不过就是不能通过自身进行实例化了。

//图形类
abstract class Shape {
    public String name; //名字
    public double size; //大小

    public void method() {
        System.out.println("普通成员方法");
    }
    public static void method1() {
        System.out.println("静态成员方法");
    }
    //使用 abstract 修饰的方法叫抽象类,方法被修饰后可以不写具体的操作
    public abstract void draw();
}

4. 当一个类继承抽象类时,如果抽象类有抽象方法必须重写父类的所有抽象类方法

不重写报错
在这里插入图片描述

重写后没报错
在这里插入图片描述

5. 当抽象类 A 继承抽象类 B,抽象类 A 可以不重写抽象类 B 的抽象方法

抽象类继承抽象类,该子类抽象类可以不重写父类抽象类
在这里插入图片描述

6. 当一个普通类继承抽象类A,而抽象类A继承抽象类Shape,此时该普通类必须重写shape和A的抽象方法,不重写会报错

在这里插入图片描述

7. final不能修饰抽象类和抽象方法

final 和 abstract 是天敌,final 是使一个类不能被继承,而使用 abstract 抽象类 是为了使这个类被继承。

在这里插入图片描述

  • 抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.
  • 有些同学可能会说了, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法呢?
    确实如此, 但是使用抽象类相当于多了一重编译器的校验.

总结:使用抽象类的目的是对子类的一种校验。

如实际工作不应该由父类完成, 而应由子类完成.那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的,但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题。



好的,到这里本章节就结束了,如发现有错误,请各位大佬及时指出。

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

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

相关文章

Birdboot第六天 jar包 数据库

实际应用birdboot框架 1.BirdBoot导包 1.新建maven BirdBoot------pom替换 2.删掉static 和 Springboot里面写的(controller entity) rebuild之后把无用的导包都删掉 主启动类里面把main方法改为run方法 传参:类名和参数(复制sp…

动力节点索引优化解决方案学习笔记——索引介绍

1.索引介绍 1.1什么是MySQL的索引 MySQL官方对于索引的定义:索引是帮助MySQL高效获取数据的数据结构。 MySQL在存储数据之外,数据库系统中还维护着满足特定查找算法的数据结构,这些数据结构以某种引用(指向)表中的数据,这样我们…

决策树算法

目录 ​分类算法 决策树算法 外卖订餐决策树 分支处理 分类算法 分类算法是利用训练样本集获得分类函数即分类模型(分类器),从而实现将数据集中的样本划分到各个类中。分类模型通过学习训练样本中属性集与类别之间的潜在关系,并以此为依据对新样本属…

测试基础——数据库及数据库表的SQL操作(了解即可)

目录 1.数据库基础概念 2.SQL介绍 3.MySQL介绍 4.数据库连接工具Navicat 5.数据类型 6.约束 7.对数据库操作的SQL语句 7.1创建数据库 7.2使用/打开/切换数据库 7.3修改数据库 7.4删除数据库 7.5查看所有数据库 7.6数据库备份 8.数据库表操作的SQL语句 8.1创建数据…

VisualSFM的配置与使用 MeshLab的网格生成与纹理添加

前言 本实验环境如下: VisualSFM版本V0.5.26 MeshLab版本2022.02 操作系统Windows10,64bit 0 VisualSFM配置 0.1 下载 VisualSFM下载链接:VisualSFM : A Visual Structure from Motion System Cmvs-Pmvs下载链接:GitHub -…

[附源码]SSM计算机毕业设计郑工校园二手交易平台网站JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

有限自动机字符串匹配

上一篇文章正则表达式,提到正则表达式是一种用来表示有限自动机所接受单词组合的语言,那么什么是有限自动机呢,以及它是如何进行字符串匹配的,下面来做详细介绍 什么是有限自动机 目前程序上利用不同的编程语言通过正则表达式进…

泰勒公式理解

文章目录1:一元泰勒展开公式2:二元泰勒展开公式3:二元函数的黑塞矩阵4:多元函数的黑塞矩阵其他链接1:一元泰勒展开公式 举例:f(x) 3x 2x 5 在x0或x1处的泰勒展开 当x0时: 当x1时&#xff…

cadence orcad capture tcl/tk脚本开发

Orcad是一个很优秀的原理图工具,orcad支持tcl/tk开发,介绍一下当前本人开发的脚本工具,可用于提高硬件工程师的画图效率。 环境准备 将压缩包解压到C盘(注意一定要C盘根目录下),C:\Tcltk。如下图所示将上图…

Selector的使用

文章目录Selector 的使用1.直接使用2. Scrapy Shell3.XPath 选择器4.CSS选择器5.正则匹配Selector 的使用 我们之前介绍了利用Beautiful Soup、pyquery 以及正则表达式来提取网页数据的方法,确实非常方便。不过Scrapy提供了自己的数据提取方法,即内置的…

[附源码]java毕业设计社区志愿者服务系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

传输中的差错检验技术

差错检验 在网络传输过程数据难免会产生错误,需要使用差错检验技术进行纠错,可靠传输技术避免错误的发生 1 术语 比特差错 误码率BER 差错检验码 2 奇偶校验(不会采用) 在待发送的数据后面添加1位奇偶校验位,使整…

MyBatis基于XML的详细使用-参数、返回结果 处理

1、参数的取值方式 在xml文件中编写sql语句的时候有两种取值的方式,分别是#{}和${}。 注意:这里推荐使用#{}的方式,可以有效的防止sql注入问题。 2、select的参数传递 1.单个参数: 不管多少个参数最好在参数前加上param注解,为其取一个别名 2.多个参数…

[网络工程师]-传输层协议-TCP拥塞控制

TCP拥塞控制的概念是:每个源端判断当前网络中有多少可用容量,从而知道它可以安全完成传送的分组数。拥塞控制解释防止过多的数据注入网络,避免网络中间设备(路由器、交换机等)过载而发生拥塞。拥塞控制是一个全局性的过…

数据结构系列学习(九) - 循环队列(Circular_Queue)

目录 引言: 学习: 循环队列设计背景: 利用顺序表的思维对队列进行探讨: 解决方案的思考: 循环队列中循环的体现: 循环队列的要点: 第一个难点: 第二个难点: 第三…

Verilog 显示任务($display, $write, $strobe, $monitor)

Verilog 中主要用以下 4 种系统任务来显示(打印)调试信息:$display, $write, $strobe, $monitor。 $display $display 使用方法和 C 语言中的 printf 函数非常类似,可以直接打印字符串,也可以在字符串中指定变量的格…

7. 微服务之Docker自动化部署

7.1 Docker 介绍 Docker 是一个快速交付应用、运行应用的技术: 可以将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意Linux操作系统运行时利用沙箱机制形成隔离容器,各个应用互不干扰启动、移除都可以通过一行命令完成&#xff…

华清远见:驱动点灯第N回目

1.在串口工具进行输入: echo 1 > /dev/myled0 ---->led1灯点亮 echo 0 > /dev/myled0 ---->led1灯熄灭 echo 1 > /dev/myled1 ---->led1灯点亮 echo 0 > /dev/myled1 ---->led1灯熄灭 echo 1 > /dev/myled2 ---->led1灯点亮 ec…

力扣刷题day52|84. 柱状图中最大的矩形

文章目录84. 柱状图中最大的矩形思路动态规划单调栈84. 柱状图中最大的矩形 力扣题目链接 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 示例 1: …

空间域图像增强处理-含Labview程序

⭕⭕ 目 录 ⭕⭕✳️ 一、引言✳️ 二、领域图像增强实例分析✳️ 2.1 线性滤波实例分析✳️ 2.2 非线性滤波实例分析✳️ 2.3 Canny边缘检测✳️ 三、Labview程序获取✳️ 一、引言 图像在其采集或传递过程中常会受到各种噪声的影响,这会导致其中包含的重要信息很…