面向对象 06:三大特性之——多态,多态的基本概念和相关使用,关键字 instanceof,以及对象间的类型转换

一、前言

记录时间 [2024-05-14]

系列文章简摘:
面向对象 02:区分面向过程与面向对象,类和对象的关系
面向对象 03:类与对象的创建、初始化和使用,通过 new 关键字调用构造方法,以及创建对象过程的内存分析
面向对象 04:三大特性之——封装,封装的含义和作用,以及在 Java 中的使用方式,附完整的测试案例代码
面向对象 05:三大特性之——继承,继承在 Java 中的相关使用,区分关键字 super 和 this,方法重写的注意点

更多 Java 相关文章,请参考专栏哦。

本文讲述面向对象编程的三大特性之——多态。通过案例分析,介绍了多态的基本概念、相关使用,以及优缺点等。此外,文章还讲述了关键字 instanceof 的使用方式,以及对象之间的类型转换。


面向对象编程(Object-Oriented Programming, OOP)的三大特性是封装、继承和多态,这三大特性是 OOP 的基础,为设计灵活、可维护和可扩展的软件系统提供了核心机制。

这三个特性共同构成了面向对象编程的基础,使开发者能够设计出高内聚、低耦合的软件系统,促进了软件工程的高效管理和复杂问题的有效解决。

  • 高内聚:一个模块内部各个组成部分(如类的方法、函数、变量等)之间应该紧密关联,共同完成一个具体且单一的功能,不允许外部干涉。
  • 低耦合:各模块之间的依赖关系应该尽可能地减少和简化,一个模块应尽量少地依赖其他模块,模块之间的接口应清晰、简单,且只暴露必要的功能给外部使用。

二、什么是多态

1. 基本概念

多态(Polymorphism)是面向对象编程的一个核心特性,即同一方法可以根据发送对象的不同而采用多种不同的行为方式

多态允许使用父类类型的引用来指向子类的对象,从而使得代码更具通用性、可扩展性和可维护性。

Java 实现多态主要依赖于以下几个关键概念:

  • 继承与多态
    • 多态的实现基于继承,即一个子类可以从父类继承方法,然后可以根据需要重写这些方法来改变其行为。
    • 当一个父类引用指向子类对象时,可以调用子类重写的方法,尽管引用的静态类型是父类,这就是多态的表现。
  • 方法重写(Override)
    • 子类可以重写(Override)父类的方法,提供自己特定的实现。这是实现多态的重要手段。
    • 重写的方法需要有相同的签名(方法名、返回类型以及参数列表)。
  • 动态绑定(Dynamic Binding / Late Binding)
    • 在 Java 中,方法的调用是在运行时绑定的,这意味着实际执行哪个版本的方法(父类的还是子类的)取决于实际对象的类型,而不是引用的类型。这一过程称为动态绑定或晚期绑定。
  • 抽象类与接口
    • 抽象类和接口为多态提供了另一种形式的实现。它们定义了方法的合同,具体的实现由子类完成,这增加了系统的灵活性和可扩展性。

2. 多态的优缺点

多态的优势:

  • 灵活性:可以使用统一的接口来操作各种类型的对象,减少代码耦合度。
  • 可扩展性:增加软件的可扩展性,易于添加新的子类而不影响现有的体系结构。
  • 简化性:提高代码的可读性和可维护性,特别是在处理大量对象时。

多态的限制:

  • 多态通常只适用于方法,不适用于属性。即使子类中重写了父类的属性,父类引用也只能访问到父类定义的属性。
  • 当使用父类引用调用一个方法时,只能访问到在父类中定义过的方法,不能访问子类特有的方法
  • 由于动态绑定,某些情况下可能会牺牲部分运行效率;过多使用向上转型可能使代码的意图不够明确。

3. 案例分析

在 Java 中,一个对象实际类型是确定的,但它可以指向的引用类型是不确定的,比如:父类的引用指向子类。

准备两个父子关系的类

举例说明,准备两个父子关系的类,其中,Animal 是父类,Dog 是子类。

在父类中写了一个方法 sound()

// Animal 父类
public class Animal {// 在父类中写了一个方法 sound(),然后将该方法在子类中重写public void sound() {System.out.println("Animal makes a sound");}}

在子类中重写了从父类中继承的 sound() 方法,同时,写了一个子类中特有的方法 play()

// Dog 子类
public class Dog extends Animal {// 在子类中重写了从父类中继承的 sound() 方法@Overridepublic void sound() {System.out.println("Dog barks");}// 写了一个子类中特有的方法 play()public void play() {System.out.println("Dog plays");}}

引用对象实例化

对于子类 Dog,它能调用的方法是自己的,或者从父类那里继承的。

父类引用可以指向子类,我们可以将父类 Animal 的引用指向子类 Dog,也可以将 Object 的引用指向子类 Dog

public class Application {public static void main(String[] args) {// 一个对象实际类型是确定的
//        new Dog();
//        new Animal();// 可以指向的引用类型是不确定的,比如:父类的引用指向子类// 子类 Dog 能调用的方法是自己的,或者从父类那里继承的Dog dog = new Dog();// 父类 Animal 可以指向子类Animal animal = new Dog();Object obj = new Dog();}}

进行测试

测试一

子类重写了父类的方法,父类对象执行子类的方法。

// 子类重写了父类的方法,父类对象执行子类的方法animal.sound();		// 调用子类方法 Dog barks
dog.sound();		// 调用子类方法 Dog barks

在这个例子中,Animal 是父类,Dog 是子类。尽管 animal 被声明为 Animal 类型,但它实际上指向的是 Dog 类的一个实例。因此,调用 sound() 方法时,执行的是 Dog 类中重写的方法,这就是多态性的体现。

测试二

父类可以指向子类,但不能调用子类独有的方法。

对象能调用哪些方法,主要看对象左边的类型,和右边关系不大。

// 父类可以指向子类,但不能调用子类独有的方法
// animal.play();
dog.play();

在这个例子中,Animal 是父类,Dog 是子类。尽管 animal 实际上指向的是 Dog 类的一个实例,但不能调用 Dog 类独有的方法 play(),该方法只有 Dog 类型的实例能调用。


4. 注意事项

以下是一些关于多态的注意事项:

注意事项:1. 多态是方法的多态,属性没有多态。2. 有联系的类才能进行类型转换(比如父类和子类),否则会抛出类型转换异常(ClassCastException)。3. 多态存在条件:继承关系,方法需要重写,父类引用指向子类  Father f1 = new Son();不能被重写的方法:1. static 方法,属于类,不属于实例2. final 常量类型3. private 私有类型补充:1. 子类重写了父类的方法,父类对象执行子类的方法。2. 父类可以指向子类,但不能调用子类独有的方法。

三、关键字 instanceof

1. 基本概念

instanceof 是 Java 中的一个关键字,用于判断一个对象是否属于某个类或其子类(或者实现了某个接口)

使用 instanceof 的一个典型场景是在需要确定对象的具体类型,以便进行特定类型的操作时。

但要,频繁使用 instanceof 可能意味着设计不够面向对象,因为良好的面向对象设计倾向于使用多态来处理不同类型的对象,而不是通过类型检查来分支逻辑。

其语法形式如下:

object instanceof ClassName

其中,object 是要检查的对象,ClassName 是类名或接口名。

如果 objectClassName 类的实例,或者是其子类的实例,或者是实现了 ClassName 接口的类的实例,那么 instanceof 表达式的结果就是 true;否则,结果是 false


2. 案例分析

准备父子类和实例对象

例如,有五个类:ObjectAnimalDogCatString

其中,ObjectAnimal 的父类,AnimalDogCat 的父类。StringObject 的子类。

父子关系:

Object > String
Object > Animal > Dog
Object > Animal > Cat

准备一些实例对象:

// 正常的实例化
Object object = new Object();
Animal animal = new Animal();
Dog dog = new Dog();// 向上转型,父类引用指向子类实例,实际是子类的对象
Object object2 = new Dog();
Animal animal2 = new Dog();

使用 instanceof 判断

判断 object 对象与上述五个类之间的关系。

// Object > String
// Object > Animal > Dog
// Object > Animal > CatSystem.out.println("Object object = new Object();");System.out.println(object instanceof Object);   // true
System.out.println(object instanceof Animal);   // false
System.out.println(object instanceof Dog);      // false
System.out.println(object instanceof Cat);      // false
System.out.println(object instanceof String);      // false

思考:通过 Object object = new Object(); 实例化 object 对象。

  • objectObject 类的对象,object instanceof Objecttrue
  • object 既不是其他四个类的对象,也不是四个类的子类的对象,故比较为 false

同理,判断 object2 对象与上述五个类之间的关系。

// Object > String
// Object > Animal > Dog
// Object > Animal > Cat// 向上转型,父类引用指向子类实例,实际是子类的对象
Object object2 = new Dog();System.out.println("Object object2 = new Dog();");System.out.println(object2 instanceof Object);  // true
System.out.println(object2 instanceof Animal);  // true
System.out.println(object2 instanceof Dog);     // true
System.out.println(object2 instanceof Cat);     // false
System.out.println(object2 instanceof String);     // false

思考:通过 Object object2 = new Dog(); 实例化 object 对象。

  • object2Dog 类的对象,object2 instanceof Dogtrue
  • object2Object 类的子类的对象,object2 instanceof Objecttrue
  • object2Animal 类的子类的对象,object2 instanceof Animaltrue
  • object2 既不是 CatString 类的对象,也不是它们的子类的对象,故比较为 false

完整的 instanceof 比较

完整的 instanceof 比较如下:

public class Application {public static void main(String[] args) {// instanceofObject object = new Object();Animal animal = new Animal();Dog dog = new Dog();Object object2 = new Dog();Animal animal2 = new Dog();System.out.println("Object object = new Object();");System.out.println(object instanceof Object);   // trueSystem.out.println(object instanceof Animal);   // falseSystem.out.println(object instanceof Dog);      // falseSystem.out.println(object instanceof Cat);      // falseSystem.out.println(object instanceof String);      // falseSystem.out.println("Animal animal = new Animal();");System.out.println(animal instanceof Object);   // trueSystem.out.println(animal instanceof Animal);   // trueSystem.out.println(animal instanceof Dog);      // falseSystem.out.println(animal instanceof Cat);      // false
//        System.out.println(animal instanceof String);      // 编译时报错System.out.println("Dog dog = new Dog();");System.out.println(dog instanceof Object);      // trueSystem.out.println(dog instanceof Animal);      // trueSystem.out.println(dog instanceof Dog);         // true
//        System.out.println(dog instanceof Cat);     // 编译时报错
//        System.out.println(dog instanceof String);     // 编译时报错System.out.println("Object object2 = new Dog();");System.out.println(object2 instanceof Object);  // trueSystem.out.println(object2 instanceof Animal);  // trueSystem.out.println(object2 instanceof Dog);     // trueSystem.out.println(object2 instanceof Cat);     // falseSystem.out.println(object2 instanceof String);     // falseSystem.out.println("Animal animal2 = new Dog();");System.out.println(animal2 instanceof Object);  // trueSystem.out.println(animal2 instanceof Animal);  // trueSystem.out.println(animal2 instanceof Dog);     // trueSystem.out.println(animal2 instanceof Cat);     // false
//        System.out.println(animal2 instanceof String);     // 编译时报错}}

四、类型转换

1. 基本概念

在 Java 中,有继承关系的对象之间的转换主要涉及向上转型(Upcasting)和向下转型(Downcasting)。

  • 向上转型(Upcasting):这是 Java 中最常见的对象转换形式,也是自动进行的,无需显式转换。将子类对象赋值给父类引用时,就发生了向上转型。向上转型是安全的,因为子类对象可以视为是父类类型的特殊实例。
  • 向下转型(Downcasting):这是将父类引用转换为子类类型的过程,必须显式进行。因为向下转型可能导致类型不匹配的问题(比如父类引用实际上并未指向子类对象),所以需要使用 (子类类型) 父类引用 的语法,并且最好在转换前使用 instanceof 检查,以避免 ClassCastException

尝试将一个对象转换为与之无继承关系的类型时,Java 会在编译时报错。如果使用强制类型转换,运行时则会抛出 ClassCastException 异常。


2. 案例分析

向上转型,例如,将子类对象赋值给父类引用。

// 子类对象赋值给父类引用
Father father = new Son();

向下转型,例如,将父类强制转换成子类。

// 将父类强制转换成子类
// 注意使用 instanceof 检查,保证转换安全性
((Son)father);

还是以上面的类为例,准备两个父子关系的类,其中,Animal 是父类,Dog 是子类。

  • 在父类 Animal 中写了一个方法 sound()
  • 在子类 Dog 中重写了从父类中继承的 sound() 方法,同时,写了一个子类中特有的方法 play()
public class Application {public static void main(String[] args) {// 对象类型之间的转换// 向上转型:子类对象赋值给父类引用// 自动完成Animal obj = new Dog();// 向下转型:将父类强制转换成子类// 这样就可以调用子类私有的方法了((Dog)obj).play();}}

五、总结

本文讲述面向对象编程的三大特性之——多态。通过案例分析,介绍了多态的基本概念、相关使用,以及优缺点等。此外,文章还讲述了关键字 instanceof 的使用方式,以及对象之间的类型转换


一些参考资料

狂神说 Java 零基础:https://www.bilibili.com/video/BV12J41137hu/
TIOBE 编程语言走势: https://www.tiobe.com/tiobe-index/
Typora 官网:https://www.typoraio.cn/
Oracle 官网:https://www.oracle.com/
Notepad++ 下载地址:https://notepad-plus.en.softonic.com/
IDEA 官网:https://www.jetbrains.com.cn/idea/
Java 开发手册:https://developer.aliyun.com/ebook/394
Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/

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

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

相关文章

CAST: Cross-Attention in Space and Time for Video Action Recognition

标题:CAST: 时空交叉注意力网络用于视频动作识别 原文链接:2311.18825v1 (arxiv.org)https://arxiv.org/pdf/2311.18825v1 源码链接:GitHub - KHU-VLL/CASThttps://github.com/KHU-VLL/CAST 发表:NeurIPS-2023(CCF A…

【打字】打字训练之针对性键盘区域练习

本文章的核心点是:使用代码生成自己想要训练的键位的词汇,然后导入到打字软件针对性练习 一个程序员突然想纠正打字习惯源于腱鞘炎,虽然使用双拼打字已经不慢了,但是姿势不是很正确,导致了腱鞘炎。 所以想着好好纠正指…

Golang——http包

Go语言内置的net/http包十分优秀,提供了http客户端和服务器的实现。 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络传输协议,所有的www文件都必须遵循这个标准。设计HTTP最初的目的是为了提供一种发布和…

消息队列选型

一、要解决的问题 1.1 异步 分析: 需要根据场景来判断。若整体链路的逻辑中,某些逻辑是不需要强实时的,滞后一段时间是允许的,同时又不会对用户带来不好的体验,那么可以使用MQ完成异步操作。 例如:秒杀场…

解锁客户需求密码:银行业数据分析在业务决策中的关键作用

一、引言 在数字化和大数据时代的浪潮下,银行业正经历着前所未有的变革。作为数据分析领域的资深专家,我深知数据分析在银行业务发展中的重要性和价值。本文将从银行业数据分析的角度出发,深入探讨相关业务场景下的数据分析应用,…

UVa11419 SAM I AM

UVa11419 SAM I AM 题目链接题意分析AC 代码 题目链接 UVA - 11419 SAM I AM 题意 给出一个 RC 大小的网格,网格上面放了一些目标。可以在网格外发射子弹,子弹会沿着垂直或者水平方向飞行,并且打掉飞行路径上的所有目标,如下图所…

Java 环境变量未生效

在配置 Java 环境变量的时候,有可能会出现修改了JDK的路径,但是Java的环境变量没有相应切换的情况。比如: 但此时在控制台使用java -version命令输出的JDK版本不是新配置的版本,依然是之前的,甚至提示找不到java命令&a…

汇昌联信科技:拼多多电商的运营流程有哪些?

在当今互联网高速发展的时代,电商平台层出不穷,其中拼多多以其独特的团购模式和低价策略迅速崛起,成为众多消费者和商家的新宠。那么,拼多多电商的运营流程究竟包含哪些环节呢?接下来,我们将从商品上架、营销推广、订…

B/S版+java开发的医院绩效考核系统maven+Visual Studio Code 医院绩效考核管理系统 提升医疗服务质量的关键

B/S版java开发的医院绩效考核系统mavenVisual Studio Code 医院绩效考核管理系统 提升医疗服务质量的关键 医院绩效评价系统的建设,优化医院绩效管理体系,规范化工作目标的设计、沟通、评价与反馈,改进和提供医院管理人员的管理能力和成效&am…

关于linux的防护,以及群集你要知道的有哪些1-系统安全及应用

1、系统账号清理 1)将非登录用户shell设为/sbin/nologin useradd -s /sbin/nologin 用户名 usermod -s /sbin/nologin 用户名 2)锁定长期不使用的账号 usermod -L 用户名 (usermod -U 解锁) passwd -l 用户名 (passwd -u 解锁)…

Nginx - location 指令(二)

location 指令 location [ | ~ | ~* | ^~ ] uri {}不讨论 location name {} 形式 官方文档有如下描述: A location can either be defined by a prefix string, or by a regular expression. Regular expressions are specified with the preceding ~* modifier (…

【Web】HNCTF 2024 题解(部分)

目录 Please_RCE_Me ezFlask GoJava ez_tp GPTS Please_RCE_Me <?php if($_GET[moran] flag){highlight_file(__FILE__);if(isset($_POST[task])&&isset($_POST[flag])){$str1 $_POST[task];$str2 $_POST[flag];if(preg_match(/system|eval|assert|call|…

Linux进程间几种通信机制

一. 简介 经过前一篇文章的学习&#xff0c; 我们知道Linux下有两种标准&#xff1a;system V标准和 Posix标准。 System V 和 POSIX 标准是操作系统提供的接口标准&#xff0c;它们规定了操作系统应该如何实现一些基本功能&#xff0c;比如线程、进程间通信、文件处理等。 …

数组的学习

一.数组定义方法&#xff1a; 方法一&#xff1a; 数组名(value0 value1 value2 ...) 方法二&#xff1a; 数组名([0]value [1]value [2]value ...) 方法三&#xff1a; 列表名"value0 value1 value2 ..." 数组名($列表名) 方法四&#xff1a; 数组名[0]"va…

暴雨分布式存储集群助重庆高校打造智慧校园

教育是国家发展的基石&#xff0c;教育兴则国家兴&#xff0c;教育强则国家强。党的二十大报告指出&#xff0c;“加快建设教育强国”&#xff0c;并提出到2035年“建成教育强国”的总体目标。随着数字时代的到来&#xff0c;以物联网、大数据、云计算和人工智能为代表的数字技…

使用torch.nn.ModuleList构建神经网络

在 PyTorch 中&#xff0c;torch.nn.ModuleList 是一个持有子模块的类&#xff0c;它是 torch.nn.Module 的一个子类。与 torch.nn.Sequential 不同&#xff0c;ModuleList 不会自动地对添加到其中的模块进行前向传播。相反&#xff0c;它主要用于存储多个模块&#xff0c;并且…

线程与进程___(一)

1、线程 Thread 类创建得线程为前台线程&#xff0c;线程池中的为后台线程&#xff0c;&#xff0c;&#xff0c;Main方法结束后&#xff0c;前台线程仍然运行&#xff0c;直到完成&#xff0c;而后台线程立刻结束。 调用线程时候不会立刻进入 Running 状态&#xff0c; 而是…

redis原生命令及项目使用

主动更新策略 缓存问题及解决 布隆过滤出现哈希冲突解决方案: 选择合适的哈希函数:布隆过滤器的性能和哈希函数的选择密切相关。选择高效、低碰撞率的哈希函数可以降低误判率。通常使用的哈希函数有 MurmurHash、FNV 等。 合理设置过滤器大小:过滤器的大小(位数组的大小)…

学习笔记——字符串(单模+多模+练习题)

单模匹配 Brute Force算法&#xff08;暴力&#xff09; 算法思想 母串和模式串字符依次配对&#xff0c;如果配对成功则继续比较后面位置是否相同&#xff0c;如果出现匹配不成功的位置&#xff0c;则j&#xff08;模式串当前的位置&#xff09;从头开始&#xff0c;i&…

Docker和Kubernetes之间的关系

Docker和Kubernetes在容器化生态系统中各自扮演着不同的角色 它们之间是互补的&#xff0c;而不是替代关系。 Docker是一个开源的容器化平台&#xff0c;它允许开发人员将应用程序及其依赖项打包到一个可移植的容器中&#xff0c;并确保这些容器可以在任何Docker环境中一致地…