【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); // 6
    bc.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; // float
    var 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); // 向上转型,运行时类型是Integer
    var 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());
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW电容器充放电监测系统

概述 为了对车用超级电容器的特性进行研究,确保其在工作时稳定可靠并有效发挥性能优势,设计了一套车用超级电容器充放电监测系统。该系统通过利用传感器、USB数据采集卡、可调直流稳压电源、电子负载以及信号调理电路,完成对各信号的采集和超…

jdevelope安装

准备 1.jdk1.8(已经安装不做记录) 2.下载jdevelope安装包 3.安装包安装jdevelope开发工具 4.创建或导入项目 下载jdevelope安装包 官网下载地址:https://edelivery.oracle.com 安装包安装jdevelope开发工具 cmd管理员权限运行安装脚本…

Codeforces Round 954 (Div. 3)(A~D题)

A. X Axis 思路: 1~10暴力枚举一下所有可能 代码: #include<bits/stdc.h> using namespace std; #define N 1000005 typedef long long ll; typedef unsigned long long ull; ll n, m, t, h, k; ll a, b, c; ll ans, num, sum, cnt; ll temp[N], f1[N], f2[N]; bool f…

Nature Communications|柔性无感智能隐形眼镜(柔性传感/可穿戴电子/柔性电子)

南京大学徐飞(Fei Xu)、陆延青(Yanqing Lu)、陈烨(Ye Chen)和江苏省人民医院袁松涛(Songtao Yuan)团队,在《Nature Communications》上发布了一篇题为“Frequency-encoded eye tracking smart contact lens for human–machine interaction”的论文。论文内容如下: 一、 摘…

科普文:一天学会shell编程

1.shell概叙 本文将从shell执行、语法、实战三个方面来讲解shell编程&#xff0c;其实shell编程就是个批处理&#xff0c;将你平时在服务器上单独执行的命令&#xff0c;按照一定要求组织起来&#xff0c;写在一起&#xff0c;然后统一执行&#xff0c;就完事了。 对于运维人员…

基于Android平台开发,仿头条新闻app

相关视频教程在某站上面(&#x1f50d;浩宇软件开发) 1. 项目模块功能思维导图 2. 项目涉及到的技术点 数据来源&#xff1a;聚合数据API使用okhttp网络请求框架获取api数据使用gson库解析json数据使用RecyclerViewadapter实现新闻列表使用SQLite数据库实现用户登录&#xff0…

【thingsbord源码编译】 显示node内存不足

编译thingsbord显示报错 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory问题原因分析 重新安装java版本 编译通过

小程序多次扫描获取sence失败------ivx

扫码图片被告知侵权了&#xff0c;删除了&#xff0c;如果有需要的同学可以自己尝试。或者直接联系我。 在微信小程序里面有一个函数 wx.getEnterOptionsSync() 功能描述 获取本次小程序启动时的参数。如果当前是冷启动&#xff0c;则返回值与 App.onLaunch 的回调参数一致&am…

前端最全面试题【最新版本2024-7月】

文章目录 最常见问题javascript篇Javascript的运行机制javascript的数据类型怎样判断变量的类型数据类型转换闭包的优缺点v-if和v-for哪个优先级更高&#xff1f; 如果两个同时出现&#xff0c;应该怎么优化得到更好的性能&#xff1f;HTML5的新特性和CSS3的新特性div 上下居中…

SpringBoot注解--11--@JSONField @JsonProperty

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一个问题&#xff1a;后端实体类isXXX开头的属性&#xff0c;传到前端后自动去掉is解决方法&#xff1a; JsonProperty和JSONField1.简介2.注解的区别2.1 底层框架不…

政安晨【零基础玩转各类开源AI项目】基于Ubuntu系统部署ComfyUI:功能最强大、模块化程度最高的Stable Diffusion图形用户界面和后台

目录 ComfyUI的特性介绍 开始安装 做点准备工作 在Conda虚拟环境中进行 依赖项的安装 运行 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 零基础玩转各类开源AI项目 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&…

Rust vs Go: 特点与应用场景分析

目录 介绍Rust的特点Go的特点Rust的应用场景Go的应用场景总结 介绍 Rust和Go&#xff08;Golang&#xff09;是现代编程语言中两个非常流行的选择。凭借各自的独特优势和广泛的应用场景&#xff0c;吸引了大量开发者的关注。本文将详细介绍Rust和Go的特点&#xff0c;并探讨它…

【理解串】

目录 一、串的基本概念二、串的基本操作及实现三、串的存储实现3.1、静态数组实现3.2、动态数组实现 四、串的朴素模式匹配4.1、算法思想4.2、代码实现 五、KMP算法5.1、算法思想5.2、求模式串的next数组5.2、代码实现 一、串的基本概念 串&#xff1a;即字符串&#xff08;st…

一行命令快速导出、导入Python的依赖环境(Python)

文章目录 一、pip1、导出2、导入 二、Conda&#xff08;简&#xff09;1、导出1、导入 一、pip 1、导出 在Pycharm的Terminal窗口输入如下命令&#xff0c;即可将环境导出至文件requirements.txt。 pip freeze > C:\Users\sdl\Deskto\requirements.txt也可以在DOS界面执行…

Python 核心编程

Python 核心编程 1. 数据类型1.1 整型 int1.2 浮点数 float1.3 布尔类型 bool1.4 字符串 str1.5 列表 list1.6 元组 tuple1.7 集合 set1.8 字典 dict 2. 逻辑结构、文件操作2.1 分支结构和三元表达2.2 循环和遍历2.3 目录和路径2.4 文件操作 3. 函数、类、异常处理3.1 函数3.2 …

[Flask笔记]一个完整的Flask程序

前面讲过Flask是一个轻量级Web开发框架&#xff0c;为什么说是轻量级的呢&#xff0c;因为它用短短几行代码就能运行起来&#xff0c;我们一起来看看最简单的flask框架。 安装Flask 在看Flask框架之前我们需要先安装flask模块&#xff0c;学过python的肯定都知道&#xff0c;…

2.5 计算机网络

声明&#xff1a;文章参考的《系统架构设计师教程&#xff08;第二版&#xff09;》&#xff0c;如有侵权&#xff0c;本人将立即修改和删除。 利用通信线路将地理上分散的、具有独立功能的计算机系统和通信设备按不同的形式连接起来&#xff0c;并依靠网络软件以及通信协议实现…

《昇思25天学习打卡营第18天|onereal》

RNN实现情感分类 概述 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&#xff0c;实现如下的效果&#xff1a; 输入: This film is terrible 正确标签: Negative 预测标签: Negative输入: This film…

Android数据库基础

目录 1、安卓数据存储方式 2、数据库事务 数据库事务的特性(ACID) 事务的隔离级别 事务总结 3、ContetProvider 作用 ​编辑 统一资源标识符URI ​编辑 MIME类型 ContentProvider主要方法 4、ContentResolver 作用 主要方法 使用案例 辅助工具类 ContentUris Uri…

matlab 有倾斜的椭圆函数图像绘制

matlab 有倾斜的椭圆函数图像绘制 有倾斜的椭圆函数图像绘制xy交叉项引入斜线负向斜线成分正向斜线成分 x^2 y^2 xy 1 &#xff08;负向&#xff09;绘制结果 x^2 y^2 - xy 1 &#xff08;正向&#xff09;绘制结果 有倾斜的椭圆函数图像绘制 为了确定椭圆的长轴和短轴的…