JavaSE——类与对象(3)

news2024/11/28 18:08:16

一、方法重写

        简单来讲,方法重写就是一个子类有一个方法,和父类的某个方法的名称,返回类型,参数一样,那么我们就说子类的这个方法覆盖了父类的那个方法。比如说:

class Animal {
    public void makeSound() {
        System.out.println("一些奇怪的声音");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪汪");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal myAnimal = new Dog();
        myAnimal.makeSound(); // 输出 "汪汪汪"
    }
}

        Dog类重写了Animal类的makeSound方法。当我们创建一个Dog对象并将其赋值给Animal类型的引用时,调用makeSound方法将输出"汪汪汪",这表明调用的是Dog类的makeSound方法,体现了多态性。注意,@Override注解是可选的,但它可以帮助编译器检查方法签名是否正确,确保方法确实被重写。 

注意,方法重写也叫方法覆盖需要满足以下条件:

  1. 子类的方法的参数和方法名称必须和父类的完全一样
  2. 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
  3. 子类方法不能缩小父类方法的访问权限。
名称发生范围方法名形参列表返回类型修饰符
重载(voerload)本类必须一样类型、个数或者顺序至少有一个不同无要求无要求
重写(override)父子类必须一样完全相同子类重写方法必须是父类方法的子类或者相同子类不能缩小父类的访问范围

 二、多态

2.1什么是多态

        多态是面向对象编程中的一个重要概念,它允许不同类型的对象对同一方法进行不同的实现。具体来说,多态性指的是通过父类的引用变量来引用子类的对象,从而实现对不同对象的统一操作。看这个例子:

// 定义一个基类 Animal
abstract class Animal {
    // 抽象方法 makeSound
    public abstract void makeSound();
}

// Dog 类继承自 Animal
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪!");
    }
}

// Cat 类也继承自 Animal
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵~");
    }
}

public class first {
    public static void main(String[] args) {
        Animal a1 = new Dog();
        Animal a2 = new Cat();
        a1.makeSound();
        a2.makeSound();
        // 输出:
        // 汪汪!
        // 喵喵~
    }
}

2.2对象的多态

  1. 一个对象的编译类型和运行类型可以不同
  2. 编译类型在定义对象时就确定了,不能改变。
  3. 运行类型是可以变换的。
  4. 初次实例化一个对象时,=左边为编译类型,=右边为运行类型。
public class first {
    public static void main(String[] args) {
        Animal a1 = new Dog();//a1的编译类型为Animal,运行类型为Dog
        Animal a2 = new Cat();//a2的编译类型为Animal,运行类型为Cat
        a1 = a2;//a1的运行类型变为Cat
    }
}

2.3多态的条件

  1. 存在继承关系的类之间才能够使用多态性。多态性通常通过一个父类用变量引用子类对象来实现
  2. 子类必须重写(Override)父类的方法。通过在子类中重新定义和实现父类的方法,可以根据子类的特点行为改变这个方法的行为,如猫和狗吃东西的独特行为。
  3. 使用父类的引用变量来引用子类对象。这样可以实现对不同类型的对象的统一操作,而具体调用哪个子类的方法会在运行时多态决定。

        关于不能调用子类的特有成员这一点是因为在能够调用那些成员是在编译阶段由编译器根据编译类型决定的。最终运行时,要依据于子类的具体实现。

2.4多态的细节

  1. 属性没有重写的说法,属性的值看编译类型
  2. instanceOf操作符,用于判断对象的类型是否为XX类型或XX类型的子类型。

三、向上转型

3.1什么是向上转型

        向上转型是指将一个子类的对象引用赋值给其父类类型的引用变量。在向上转型中,子类对象可以被视为父类对象,可以使用父类类型的引用变量来引用子类对象。这样做的好处是可以以统一的方式处理不同类型的对象。

父类类型 引用名 = new 子类类型();

        编译类型看左边,运行类型看右边。通过这个引用名,可以调用父类所有成员(需要遵守访问权限),不能调用子类中的特有成员。  

3.2向上转型的规则

  1. 子类对象可以隐式地转型为父类对象,不需要任何显式的类型转换操作。

  2. 父类引用变量可以引用子类对象,但通过父类引用变量只能访问到子类对象中定义的父类成员,无法访问子类独有的成员。

  3. 子类对象中重写的方法,在通过父类引用变量调用时,会调用子类中的实现(动态绑定)。

  4. 向上转型是安全的操作,因为子类对象本身就是一个父类对象。

class Animal {
    public void eat() {
        System.out.println("Animal is eating.");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Dog is eating.");
    }

    public void bark() {
        System.out.println("Dog is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();  // 向上转型
        animal.eat();  // 调用的是 Dog 类中的 eat() 方法
        // animal.bark();  // 错误:无法访问 Dog 类中独有的方法

        Dog dog = (Dog) animal;  // 向下转型
        dog.bark();  // 调用 Dog 类中的 bark() 方法
    }
}

四、向下转型

4.1什么是向下转型

        向下转型(Downcasting)是指将一个父类类型的引用变量转换为其子类类型的引用变量。它与向上转型相反,需要进行显式的类型转换操作。

        在某些情况下,当一个对象被向上转型后,它的具体类型信息会丢失,只保留了父类类型的信息。如果我们需要访问子类中特有的成员或调用子类重写的方法,就需要使用向下转型。

子类类型 引用名 = (子类类型) 父类引用;

4.2向下转型的规则

  1. 只能强转父类的引用,不能强转父类的对象。
  2. 要求当前被强转的父类的引用必须指向的是当前目标类型的对象。
  3. 可以调用子类类型中所有的成员。
class Animal {
    public void eat() {
        System.out.println("Animal is eating.");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("Dog is eating.");
    }

    public void bark() {
        System.out.println("Dog is barking.");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal = new Dog();  // 向上转型

        // 使用向下转型之前,需要先检查对象是否实际上是子类的实例
        if (animal instanceof Dog) {
            Dog dog = (Dog) animal;  // 向下转型
            dog.bark();  // 调用 Dog 类中的 bark() 方法
        } else {
            System.out.println("animal is not an instance of Dog");
        }
    }
}

五、动态绑定

5.1什么是动态绑定

        当一个方法被声明为非静态且非私有时,在继承结构中,如果子类重写了该方法,则具体执行哪个版本的方法是在运行时确定的。这与静态绑定不同,静态绑定(编译时绑定)发生在编译阶段,此时确定了方法的具体实现。这种机制是多态的核心,它使得基类的引用能够根据实际对象类型调用相应的方法实现。

5.2Java的动态绑定机制

  1. 当调用对象方法时,该方法会和该对象的运行类型绑定
  2. 当调用对象属性时,没有动态类型绑定,哪里声明,那里使用。

看这个例子:

class A{
    public int i = 10;
    public int sum(){
        return get() + 5;
    }

    public int get(){
        return i;
    }

    public int sum1(){
        return i + 5;
    }
}

class B extends A{
    public int i = 20;

    public int sum(){
        return get()+ 20;
    }

    public int sum1(){
        return i + 10;
    }

    public int get(){
        return i;
    }
}

public class first{
    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.sum());//40
        System.out.println(a.sum1());//30
    }
}

        在这段代码中,a.sum()指令,直接调用了B类中的sum方法,在sum方法调用了B类的get方法,所以结果是40。如果将B类的sum方法注释掉,会输出什么呢?

        由于B类没有对应的sum方法,会根据继承的规则查找A类是否有sum方法。这里有一个问题,A类的sum方法调用了get方法,但是A类和B类都有get方法,这里应该调用哪一个get方法呢?根据动态绑定规则:当调用对象方法时,该方法会和该对象的运行类型绑定。所以应该优先调用其绑定类型即B类中的get方法,又根据动态绑定规则:当调用对象属性时,没有动态类型绑定,哪里声明,那里使用。所以返回的是B类的i值,输出应该为20+5 = 25。

        如果将B类中的get方法也注释掉,这时应当根据继承的规则去A类中查找get方法,但是这个A类的get方法应该返回A的i,所以输出应该为10+5 = 15。

        如果不注释掉B类中的get方法,转而注释掉B类的i,答案也会是10+5 = 15。

六、多态数组

        多态数组是指数组中的元素可以是某个基类的实例,也可以是该基类的任何子类的实例。通常情况是数组类型定义为父类类型,而里面保存的实际元素类型为子类类型实际达到的效果就是父类引用指向子类对象

// 基类 Shape
abstract class Shape {
    public abstract void draw();
}

// 子类 Circle 继承自 Shape
class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

// 子类 Rectangle 继承自 Shape
class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle.");
    }
}

public class PolymorphicArrayExample {
    public static void main(String[] args) {
        // 创建一个 Shape 类型的数组
        Shape[] shapes = new Shape[2];

        // 向上转型:将 Circle 和 Rectangle 的实例放入数组
        shapes[0] = new Circle();
        shapes[1] = new Rectangle();

        // 遍历数组并调用 draw 方法
        for (Shape shape : shapes) {
            shape.draw();  // 动态绑定,根据实际对象类型调用相应的方法
        }

        // 输出:
        // Drawing a circle.
        // Drawing a rectangle.
    }
}

七、多态参数

      多态参数是指在方法或构造函数中使用一个基类类型作为形参,但实际传递给该方法或构造函数的对象可以是这个基类的任何子类实例,每传入一个子类对象,都相当于形成了一次多态

// 基类 Shape
abstract class Shape {
    public abstract void draw();
}

// 子类 Circle 继承自 Shape
class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a circle.");
    }
}

// 子类 Rectangle 继承自 Shape
class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.println("Drawing a rectangle.");
    }
}

public class PolymorphicParameterExample {
    // 方法接受一个 Shape 类型的参数
    public static void display(Shape shape) {
        shape.draw();  // 动态绑定,根据实际对象类型调用相应的方法
    }

    public static void main(String[] args) {
        // 创建 Circle 和 Rectangle 的实例
        Circle circle = new Circle();
        Rectangle rectangle = new Rectangle();

        // 传递不同类型的对象给 display 方法
        display(circle);  // 输出: Drawing a circle.
        display(rectangle);  // 输出: Drawing a rectangle.
    }
}

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

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

相关文章

数据结构C语言描述5(图文结合)--广义表讲解与实现

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法;有C基础即可跟着学习,代码均可运行;准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言…

23种设计模式-装饰器(Decorator)设计模式

文章目录 一.什么是装饰器设计模式?二.装饰器模式的特点三.装饰器模式的结构四.装饰器模式的优缺点五.装饰器模式的 C 实现六.装饰器模式的 Java 实现七.代码解析八.总结 类图: 装饰器设计模式类图 一.什么是装饰器设计模式? 装饰器模式&…

构建英语知识网站:Spring Boot框架解析

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…

数据结构之数组与链表的差异

一、数组 数组(Array)是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。利用元素的索引(index)可以计算出该元素对应的存储地址。最简单的数据结构类型是一维数组…

RabbitMQ7:消息转换器

欢迎来到“雪碧聊技术”CSDN博客! 在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将…

Ubuntu20.04+ROS 进行机械臂抓取仿真:环境搭建(一)

目录 一、从官网上下载UR机械臂 二、给UR机械臂添加夹爪 三、报错解决 本文详细介绍如何在Ubuntu20.04ROS环境中为Universal Robots的UR机械臂添加夹爪。首先从官方和第三方源下载必要的软件包,包括UR机械臂驱动、夹爪插件和相关依赖。然后,针对gazeb…

(即插即用模块-Attention部分) 二十、(2021) GAA 门控轴向注意力

文章目录 1、Gated Axial-Attention2、代码实现 paper:Medical Transformer: Gated Axial-Attention for Medical Image Segmentation Code:https://github.com/jeya-maria-jose/Medical-Transformer 1、Gated Axial-Attention 论文首先分析了 ViTs 在训…

Git 进程占用报错-解决方案

背景 大仓库,由于开发者分支较多,我们在使用 git pull 或 git push 等命令时(与远端仓库交互的命令),不知之前配置了什么,我的电脑会必现以下报错(有非常长一大串报错-不同分支的git进程占用报…

【FPGA-MicroBlaze】串口收发以及相关函数讲解

前言 工具:Vivado2018.3及其所对应的SDK版本 目前网上有许多MicroBlaze 的入门教程,比如下面的这个参考文章,用串口打印一个hello world。 【FPGA】Xilinx MicroBlaze软核使用第一节:Hello World!_fpga软核microblaze-CSDN博客 个…

代码美学2:MATLAB制作渐变色

效果: %代码美学:MATLAB制作渐变色 % 创建一个10x10的矩阵来表示热力图的数据 data reshape(1:100, [10, 10]);% 创建热力图 figure; imagesc(data);% 设置颜色映射为“cool” colormap(cool);% 在热力图上添加边框 axis on; grid on;% 设置热力图的颜色…

Android下载出现open failed: EPERM (Operation not permitted)

今天帮忙给同事调一下apk,发现android 自动更新apk,下载apk的时候总是失败,总是卡在 输出流这一步了 于是第一步分析,立马想到权限 但是下载之前的读写内存的权限也都有了 什么android 10高版本的不开启分区存储也用了 android…

使用爬虫时,如何确保数据的准确性?

在数字化时代,数据的准确性对于决策和分析至关重要。本文将探讨如何在使用Python爬虫时确保数据的准确性,并提供代码示例。 1. 数据清洗 数据清洗是确保数据准确性的首要步骤。在爬取数据后,需要对数据进行清洗,去除重复、无效和…

uniapp中使用Mescroll实现下拉刷新与上拉加载项目实战

如何在UniApp中使用Mescroll实现下拉刷新与上拉加载 前言 下拉刷新和上拉加载更多成为了提升用户体验不可或缺的功能。UniApp作为一个跨平台的应用开发框架,支持使用Vue.js语法编写多端(iOS、Android、H5等)应用。Mescroll作为一款专为Vue设…

【接口自动化测试】一文从0到1详解接口测试协议!

接口自动化测试是软件开发过程中重要的环节之一。通过对接口进行测试,可以验证接口的功能和性能,确保系统正常运行。本文将从零开始详细介绍接口测试的协议和规范。 定义接口测试协议 接口测试协议是指用于描述接口测试的规范和约定。它包含了接口的请求…

RAG数据拆分之PDF

引言RAG数据简介PDF解析方法及工具代码实现总结 二、正文内容 引言 本文将介绍如何将RAG数据拆分至PDF格式,并探讨PDF解析的方法和工具,最后提供代码示例。 RAG数据简介 RAG(关系型属性图)是一种用于表示实体及其关系的图数据…

【开源项目】2024最新PHP在线客服系统源码/带预知消息/带搭建教程

简介 随着人工智能技术的飞速发展,AI驱动的在线客服系统已经成为企业提升客户服务质量和效率的重要工具。本文将探讨AI在线客服系统的理论基础,并展示如何使用PHP语言实现一个简单的AI客服系统。源码仓库地址:ym.fzapp.top 在线客服系统的…

WEB攻防-通用漏洞XSS跨站MXSSUXSSFlashXSSPDFXSS

演示案例: UXSS-Edge&CVE-2021-34506 FlashXSS-PHPWind&SWF反编译 PDFXSS-PDF动作添加&文件上传 使用jpexs反编译swf文件 上传后,发给别人带漏洞的分享链接

QSqlTableModel的使用

实例功能 这边使用一个实例显示数据库 demodb 中 employee 数据表的内容,实现编辑、插入、删除的操作,实现数据的排序和记录过滤,还实现 BLOB 类型字段 Photo 中存储照片的显示、导入等操作,运行界面如下图: 在上图中…

适用于学校、医院等低压用电场所的智能安全配电装置

引言 电力,作为一种清洁且高效的能源,极大地促进了现代生活的便捷与舒适。然而,与此同时,因使用不当或维护缺失等问题,漏电、触电事件以及电气火灾频发,对人们的生命安全和财产安全构成了严重威胁&#xf…

LabVIEW实现UDP通信

目录 1、UDP通信原理 2、硬件环境部署 3、云端环境部署 4、UDP通信函数 5、程序架构 6、前面板设计 7、程序框图设计 8、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合…