【Java16】多态

向上类型转换

对于引用变量,在程序中有两种形态:一种是编译时类型,这种引用变量的类型在声明它的时候就决定了;另一种则是运行时类型,这种变量的类型由实际赋给它的对象决定。

当一个引用变量的编译时类型和运行时类型不一致时,就出现了多态(Polymorphism)

对面向对象语言来说,所有的对象(Object),或者说类的实例,本质上都是引用变量。因此,多态最主要就是针对对象来说的:声明时引用变量指向的对象的类型,和运行时引用变量指向的对象的类型不一致。

在这里插入图片描述

class BaseClass
{public int book = 6;public void base(){System.out.println("父类的普通方法");}public void test(){System.out.println("父类被覆盖的方法");}
}public class SubClass extends BaseClass
{// 覆盖public String book = "Java疯狂讲义"; // 同名实例public void test(){System.out.println("子类的覆盖父类的方法");}public void sub(){System.out.println("子类的普通方法");}public static void main(String[] args){var bc = new BaseClass(); // 声明一个BaseClass的对象,编译时和运行时的类型一致,不存在多态System.out.println(bc.book); // 6bc.base(); // 父类的方法bc.test(); // 父类的方法//-------------var sc = new SubClass(); // 声明一个SubClass的对象,同样不存在多态System.out.println(sc.book); // 子类实例变量覆盖了父类的实例变量,输出"Java疯狂讲义"sc.base(); // 子类方法覆盖了父类的方法sc.test(); // 子类的普通方法//-------------BaseClass polymophicBC = new SubClass(); // 编译时类型是BaseClass,运行时类型是SubClass,发生了多态System.out.println(polymophicBC.book); // 输出6,是父类的实例变量polymophicBC.base(); // 执行父类的base方法polymophicBC.test(); // 执行当前类,也就是运行时类型SubClass的test方法// polymophicBC的编译时类型是BaseClass,没有提供sub方法// 因此调用sub方法时会出现编译错误// polymophicBC.sub();}
}
  • 28~31行是标准的对象的声明与使用;
  • 33~36行是标准的继承;
  • 38~41行出现了多态。

对变量polymophicBC来说,编译时类型是BaseClass(声明语句左端),运行时类型是SubClass(声明语句右端)。

把一个子类对象赋给一个父类引用变量,在这个过程中发生了什么?

类型转换

多态在Java中实现的机制就是把子类对象赋值给父类引用变量,这实际上就是一种类型装换,具体也叫向上转型(up-casting)。这种类型转换由系统自动完成。

从声明语句左边来看:

  • BaseClass bc = new BaseClass();
  • BaseClass polymophicBC = new SubClass();

bcpolymophicBC都是BaseClass引用类型,但是它俩在执行同名函数test()时却产生了不同的结果。这种调用同一个方法却出现不同行为特征的现象,就是多态

多态机制下,父类引用变量在运行时总是调用子类的方法,也就是说呈现出子类的行为特征而不是父类的行为特征。

对象的实例变量不具有多态性。

  • 第39行,book仍然是父类的实例变量。

引用变量在编译阶段只能调用其编译时类型拥有的方法,但是在运行时可以执行其运行时类型拥有的方法。

  • 第44行,BaseClass不具有sub()方法,因此不能调用,发生编译错误;
  • 但第41行,BaseClass具有test()方法,因此可以调用,且在运行时执行的是SubClass的同名方法。

使用var时,并不能改变编译时类型,因此也可能会发生多态:

var v1 = new SubClass(); // 自动推断是SubClass,没有多态
var v2 = polymophicBC(); // 赋值,v2自动推断是BaseClass
// 此时调用sub方法,遵照多态机制,会发生编译错误
// v2.sub();
强制类型转换

按照上面规则,引用变量只能调用编译时类型拥有的方法,即使它的运行时类型对象实际上包含了远不止这些方法。

如何让这个引用变量调用运行时类型所拥有的方法呢?

既然普通的多态依赖的是向上转型,即把子类对象赋给父类引用变量,类似于我们把double基本变量赋给float。那么也可以反过来,执行强制类型转换

强制类型转换借助类型转换运算符,和C++类似,就是()

类型转换运算符可以实现基本类型之间的转型,也能实现引用变量的转型。

请注意,强制类型转换不是万能的,受到如下约束:

  • 基本类型之间转型只能在数值类型中进行(整数型、字符型、浮点型)。数值型和布尔型之间不能转换(C++中是可以的)。
  • 引用类型转换只能在具有继承关系(直接继承或间接继承都行)的类型之间进行。

强制类型转换在这里,就是把父类实例转换为子类类型。即其编译时类型是父类类型,运行时类型是子类类型。这时候可以使用强制类型转换。

public class ConversionTest
{public static void main(String[] args){var d = 13.4; // floatvar l = (long) d; // 强制类型转换//------var in = 5; // int// var b = (boolean) in; // 错误,数值型不能转换为布尔型//------Object obj = "Hello"; // 向上转型,"Hello"是String,是Object的子类。这实际上就是多态,只不过这时候obj不能执行String拥有的方法var objStr = (String) obj; // 强制类型转换,父类/基类和子类,正常System.out.println(objStr); // 做为String类型输出//------Object objPri = Integer.valueOf(5); // 向上转型,运行时类型是Integervar in = (Integer) objPri; // 强制类型转换,基类和子类,正常// var str = (String) objPri; // objPri运行时时Integer,和String不存在继承关系,运行时会报错(类型转换异常,ClassCastException)}
}

再解读一下第12行:

  • objStr,虽然使用了var,但由于使用了强制类型转换符(String),自动推断它是String类型;
  • 此时objObject类型;
  • 因此,将obj赋值给objStr,实际上是把父类对象赋值给子类引用变量,这就和之前的upcasting正好相反,我们也可以称之为downcasting
小结
  1. 把子类对象(右)赋给父类引用变量(左)时,触发向上转型,这种转型是自动的、总是成功的。这种转型表明这个引用变量编译时是父类类型,运行时是子类类型。它表现出的是子类的行为方式,但是编译时不能调用子类的方法。同时,实例变量仍然是父类的。
  2. 使用强制类型转换可以把一个引用变量转换成其子类类型。这种转换必须是显式的,而且不一定成功(若两端不存在继承关系)。
instanceof

使用instanceof运算符可以判断是否可以执行类型转换,以避免出现ClassCastException

if (objPri instanceof String)
{var str = (String) objPri;
}

instanceof用来判断前面的对象是否是后面的类或者其子类的实例,是的话返回true,否则返回false

在Java 17中,为instanceof增加了快捷用法,来简化上面的判断代码块:

// 传统instanceof,先判断,再转换,最后使用
if (obj instanceof String) // 先判断
{var s = (String) obj; // 再转换System.out.println(s.toUpperCase()); // 最后使用
}// Java 17的模式匹配,同时完成判断和类型转换
if (obj instanceof String s)
{System.out.println(s.toUpperCase());
}

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

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

相关文章

【Pytorch】Conda环境pack打包迁移报错处理

文章目录 Anaconda虚拟环境打包一、源电脑的环境打包1.安装conda-pack工具2.确定环境3.打包环境4.将打包环境拷贝到U盘 二、环境迁移到目标电脑上三、异常处理pip install -e. 导致无法pack→忽略管理的文件已经被删除或者被覆盖→压缩成tar注意 重新激活环境 Anaconda虚拟环境…

14 - matlab m_map地学绘图工具基础函数 - 一些数据转换函数(一)

14 - matlab m_map地学绘图工具基础函数 - 一些数据转换函数(一) 0. 引言1. 关于m_ll2xy和m_xy2ll2. 关于m_lldist3. 关于m_xydist4 关于m_fdist5 关于m_idist6. 总结 0. 引言 通过前面篇节已经将m_map绘图工具中大多绘图有关的函数进行过介绍&#xff0…

Nuxt3封装网络请求 useFetch $fetch

前言: 刚接触、搭建Nuxt3项目的过程还是有点懵的,有种摸石头过河的感觉,对于网络请求这块,与之前的Vue3项目有所区别,在Vue项目通常使用axios这个库进行网络请求,但在Nuxt项目并不推荐,因为有内…

RK3568平台(显示篇)主屏副屏配置

一.主屏副屏配置 目前在RK3568平台上有两路HDMIOUT输出,分别输出到两个屏幕上,一路配置为主屏,一路配置为副屏。 硬件原理图: &hdmi0_in_vp2 {status "okay"; };&hdmi1_in_vp0 {status "okay"; }…

axios使用sm2加密数据后请求参数多了双引号解决方法

axios使用sm2加密数据后请求参数多了双引号解决 背景问题描述解决过程 背景 因项目安全要求,需对传给后端的入参加密,将请求参数加密后再传给后端 前期将axios降低到1.6.7后解决了问题,但最近axios有漏洞,安全要求对版本升级&…

【Qt 初识 Test】用图形化和代码的方式实现简单的Qt程序

文章目录 1. 通过图形化的方式实现🍎2. 通过代码的方式实现 1. 通过图形化的方式实现🍎 在界面创建出一个控件,显示 hello world,通过拖拽的方式实现; widget.ui文件如下:🔍 生成的 ui_widget.…

【mybatis】mybatisX插件概述

一、主要功能 智能补全与提示 MyBatisX 可以智能地提示和补全 SQL 语句中的关键字、表名、列名等信息,从而显著提高开发效率。代码生成器 虽然 MyBatisX 本身可能不直接提供一个完整的、独立的代码生成器,但它可能集成了或支持与其他代码生成工具&#…

卤味江湖中,周黑鸭究竟该抓住什么赛点?

近年来,卤味江湖的决斗从未停止。 随着休闲卤味、佐餐卤味等细分赛道逐渐形成,“卤味三巨头”(周黑鸭、绝味食品、煌上煌)的牌桌上有了更多新对手,赛道变挤了,“周黑鸭们”也到了转型关键期。 这个夏天&a…

MySQL字符串相关数据处理函数

目录 1. 转大小写 2. 截取字符串 sunstr 3. 获取字符长度 4. 字符串拼接 concat 5. 去掉空白 trim 1. 转大小写 转大写:upper() 转小写:lower() 虽然MySQL不严格区分大小写,但是我们还是需要掌握这种大小写的操作以方便学习其他…

Nessus相关

tenable 1 安装nessus scanner 1 )安装nessus scanner: 方法一 curl -H X-Key: xxxxx https://cloud.tenable.com/install/scanner?namescanner-name&groupsscanner-group | bash方法二: **# for ubuntu, its https://www.tenable.com/downloads/api/v1/pu…

Google登录时人机身份验证的图片类型和通过的经验建议,以及一些常见问题

很多朋友在登录谷歌账号时,都遇到过要求人机身份验证的步骤,而且有一些时候人机身份验证这个步骤很让人纠结,甚至压根就出不来具体的验证图片,或者花了十几分钟、几十分钟都过不去。 所以今天GG账号服务就来为您解析一下谷歌登录…

初学SpringMVC之接收请求参数及数据回显

pom.xml 文件导入 lombok 的依赖 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.34</version></dependency> Controller 表示这是一个控制器 RequestParam 表示从前端接收…

夏日智启:我的Datawhale AI夏令营探索之旅

前言 最近几年&#xff0c;AI&#xff08;人工智能&#xff09;的发展呈现出了前所未有的迅猛势头&#xff0c;其影响力和应用范围不断扩大&#xff0c;深刻地改变着我们的生活、工作和社会结构。尤其是AI大模型技术&#xff0c;国内外可谓是“百模大战”&#xff0c;百舸争流…

github恢复码怎么备份

https://docs.github.com/zh/authentication/securing-your-account-with-two-factor-authentication-2fa/configuring-two-factor-authentication-recovery-methods

谷歌插件之一键关闭同域名页面

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 谷歌插件之一键关闭同域名页面 前言项目结构mainfest.jsonbackgroud.js 项目实现效果展示展望 前…

13019.CUDA问题积累

文章目录 1 内存不断增长的问题1.1 主机从GPU拷贝内存1.1.1 htop 内存增长到一定阶段后&#xff0c;保持稳定 1.2 GPU拷贝到Host修改之后内存稳定无变化1.3 结论 2 主机与GPU数据拷贝方案2.1 cudaMemcpy 拷贝内存2.2 cudaMemcpyAsync 异步数据拷贝2.3 采用多线程拷贝技术2.3.1 …

群主必学!轻松Get如何解散微信群的技巧

作为一个微信群的群主&#xff0c;解散群聊可能是你需要掌握的重要技能之一。不管是因为群聊的目的已经达成&#xff0c;还是因为群成员过少或不活跃&#xff0c;了解如何解散微信群都能帮助你更好地管理你的群聊。 如何解散微信群&#xff1f;本文将为您提供一些简单易行的技…

代码随想录算法训练营第五十天| 739. 每日温度、496.下一个更大元素 I、503.下一个更大元素II

739. 每日温度 题目链接&#xff1a; 739. 每日温度 文档讲解&#xff1a;代码随想录 状态&#xff1a;不会 思路&#xff1a; 这道题需要找到下一个更大元素。 使用栈来存储未找到更高温度的下标&#xff0c;那么栈中的下标对应的温度从栈底到栈顶是递减的。这意味着&#xff…

改变Ubuntu的Tab没有缩进4格(Makefile)

1.vim里的Tab 用vi指令打开这个文件&#xff0c;没有的话就新创建一个 vi ~/.vimrc在打开的文件中输入以下两行 1 set tabstop42 set shiftwidth4 ~ Esc &#xff1a; x&#xff0c;保存并退出即可 资料来源&#xff1a; 2024年5月21日-vi/vim …

Linux Ubuntu MySQL环境安装

1. 更新软件源 首先&#xff0c;确保你的Ubuntu系统已经更新了软件源列表&#xff0c;以便能够下载到最新的软件包。打开终端并输入以下命令&#xff1a; sudo apt update 2. 安装MySQL服务器 打开终端并输入以下命令来安装MySQL服务器 sudo apt install mysql-server 在…