十九、类型信息(1)

本章概要

  • 为什么需要 RTTI

RTTI(RunTime Type Information,运行时类型信息)能够在程序运行时发现和使用类型信息

RTTI 把我们从只能在编译期进行面向类型操作的禁锢中解脱了出来,并且让我们可以使用某些非常强大的程序。对 RTTI 的需要,揭示了面向对象设计中许多有趣(并且复杂)的特性,同时也带来了关于如何组织程序的基本问题。

本章将讨论 Java 是如何在运行时识别对象和类信息的。主要有两种方式:

  1. “传统的” RTTI:假定我们在编译时已经知道了所有的类型;
  2. “反射”机制:允许我们在运行时发现和使用类的信息。

为什么需要 RTTI

下面看一下我们已经很熟悉的一个例子,它使用了多态的类层次结构。基类 Shape 是泛化的类型,从它派生出了三个具体类: CircleSquareTriangle(见下图所示)。

在这里插入图片描述

这是一个典型的类层次结构图,基类位于顶部,派生类向下扩展。面向对象编程的一个基本目的是:让代码只操纵对基类(这里即 Shape )的引用。这样,如果你想添加一个新类(比如从 Shape 派生出 Rhomboid)来扩展程序,就不会影响原来的代码。在这个例子中,Shape 接口中动态绑定了 draw() 方法,这样做的目的就是让客户端程序员可以使用泛化的 Shape 引用来调用 draw()draw() 方法在所有派生类里都会被覆盖,而且由于它是动态绑定的,所以即使通过 Shape 引用来调用它,也能产生恰当的行为,这就是多态。

因此,我们通常会创建一个具体的对象(CircleSquare 或者 Triangle),把它向上转型成 Shape (忽略对象的具体类型),并且在后面的程序中使用 Shape 引用来调用在具体对象中被重载的方法(如 draw())。

代码如下:

import java.util.stream.*;abstract class Shape {void draw() {System.out.println(this + ".draw()");}@Overridepublic abstract String toString();
}class Circle extends Shape {@Overridepublic String toString() {return "Circle";}
}class Square extends Shape {@Overridepublic String toString() {return "Square";}
}class Triangle extends Shape {@Overridepublic String toString() {return "Triangle";}
}public class Shapes {public static void main(String[] args) {Stream.of(new Circle(), new Square(), new Triangle()).forEach(Shape::draw);}
}

输出结果:

在这里插入图片描述

基类中包含 draw() 方法,它通过传递 this 参数传递给 System.out.println(),间接地使用 toString() 打印类标识符(注意:这里将 toString() 声明为 abstract,以此强制继承者覆盖该方法,并防止对 Shape 的实例化)。如果某个对象出现在字符串表达式中(涉及"+"和字符串对象的表达式),toString() 方法就会被自动调用,以生成表示该对象的 String。每个派生类都要覆盖(从 Object 继承来的)toString() 方法,这样 draw() 在不同情况下就打印出不同的消息(多态)。

这个例子中,在把 Shape 对象放入 Stream<Shape> 中时就会进行向上转型(隐式),但在向上转型的时候也丢失了这些对象的具体类型。对 stream 而言,它们只是 Shape 对象。

严格来说,Stream<Shape> 实际上是把放入其中的所有对象都当做 Object 对象来持有,只是取元素时会自动将其类型转为 Shape。这也是 RTTI 最基本的使用形式,因为在 Java 中,所有类型转换的正确性检查都是在运行时进行的。这也正是 RTTI 的含义所在:在运行时,识别一个对象的类型。

另外在这个例子中,类型转换并不彻底:Object 被转型为 Shape ,而不是 CircleSquare 或者 Triangle。这是因为目前我们只能确保这个 Stream<Shape> 保存的都是 Shape

  • 编译期,stream 和 Java 泛型系统确保放入 stream 的都是 Shape 对象(Shape 子类的对象也可视为 Shape 的对象),否则编译器会报错;
  • 运行时,自动类型转换确保了从 stream 中取出的对象都是 Shape 类型。

接下来就是多态机制的事了,Shape 对象实际执行什么样的代码,是由引用所指向的具体对象(CircleSquare 或者 Triangle)决定的。这也符合我们编写代码的一般需求,通常,我们希望大部分代码尽可能少了解对象的具体类型,而是只与对象家族中的一个通用表示打交道(本例中即为 Shape)。这样,代码会更容易写,更易读和维护;设计也更容易实现,更易于理解和修改。所以多态是面向对象的基本目标。

但是,有时你会碰到一些编程问题,在这些问题中如果你能知道某个泛化引用的具体类型,就可以把问题轻松解决。例如,假设我们允许用户将某些几何形状高亮显示,现在希望找到屏幕上所有高亮显示的三角形;或者,我们现在需要旋转所有图形,但是想跳过圆形(因为圆形旋转没有意义)。这时我们就希望知道 Stream<Shape> 里边的形状具体是什么类型,而 Java 实际上也满足了我们的这种需求。使用 RTTI,我们可以查询某个 Shape 引用所指向对象的确切类型,然后选择或者剔除特例。

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

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

相关文章

第十三章:L2JMobius学习 – 玩家攻击怪物

本章节&#xff0c;我们学习一下玩家周边怪物的刷新。在上一章节中&#xff0c;我们提过这个事情。当玩家移动完毕之后&#xff0c;会显示周围的游戏对象&#xff0c;其中就包括NPC怪物。当然&#xff0c;玩家“孵化”自己&#xff08;调用spawnMe方法&#xff09;的时候&#…

Hadoop分布式安装

首先准备好三台服务器或者虚拟机&#xff0c;我本机安装了三个虚拟机&#xff0c;安装虚拟机的步骤参考我之前的一篇 virtualBox虚拟机安装多个主机访问虚拟机虚拟机访问外网配置-CSDN博客 jdk安装 参考文档&#xff1a;Linux 环境下安装JDK1.8并配置环境变量_linux安装jdk1.8并…

Zoho Mail荣登福布斯2023年企业邮箱榜单,引领行业新方向!

几十年来&#xff0c;电子邮件一直是电子通信的重要形式&#xff0c;并且在未来的许多年里&#xff0c;它可能会无处不在。尽管有大量免费电子邮件服务可供用户和企业使用&#xff0c;但其中许多服务缺乏专门的功能&#xff0c;例如适合办公室使用的集中管理。 福布斯小型企业顾…

1024特别剪辑: 使用Python Turtle 库绘制一棵随机生成的树

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

MYSQL(事务+锁+MVCC+SQL执行流程)理解(2)

一)MYSQL中的锁(知识补充) 可以通过In_use字段来进行判断是否针对于表进行加了锁 1)对于undo log日志来说:新增类型的&#xff0c;在事务提交之后就可以清除掉了&#xff0c;修改类型的&#xff0c;事务提交之后不能立即清除掉这些日志会用于mvcc只有当没有事务用到该版本信息时…

【原创】解决Kotlin无法使用@Slf4j注解的问题

前言 主要还是辟谣之前的网上的用法&#xff0c;当然也会给出最终的使用方法。这可是Kotlin&#xff0c;关Slf4j何事&#xff01;&#xff1f; 辟谣内容&#xff1a;创建注解来解决这个问题 例如&#xff1a; Target(AnnotationTarget.CLASS) Retention(AnnotationRetentio…

等离子体共振和ENZ模式的场增强效应提高ITO对THz产生的非线性响应

利用等离子体共振和ENZ模式的场增强效应提高ITO对THz产生的非线性响应,SRR超表面的共振被设计成与λENZ紧密对齐。然而&#xff0c;ITO薄膜的加入&#xff0c;强烈地改变了透射光谱。 在x偏振照明下观察到共振分裂,在λENZ周围出现了一个明显的透明窗口,类似于等离子体诱导的透…

Spark内核调度

目录 一、DAG &#xff08;1&#xff09;概念 &#xff08;2&#xff09;Job和Action关系 &#xff08;3&#xff09;DAG的宽窄依赖关系和阶段划分 二、Spark内存迭代计算 三、spark的并行度 &#xff08;1&#xff09;并行度设置 &#xff08;2&#xff09;集群中如何规划并…

javascript IP地址正则表达式

/^(1[0-9]{2}|2[0-4][0-9]|25[0-5]|(\d){1,2})\.(1[0-9]{2}|2[0-4][0-9]|25[0-5]|(\d){1,2}|0)\.(1[0-9]{2}|2[0-4][0-9]|25[0-5]|(\d){1,2}|0)\.(1[0-9]{2}|2[0-4][0-9]|25[0-5]|(\d){1,2}|0)$/g.test(10.2.35.8) 注&#xff1a; 一定不要把表达式赋值给变量&#xff0c;直接…

软考-网络安全审计技术原理与应用

本文为作者学习文章&#xff0c;按作者习惯写成&#xff0c;如有错误或需要追加内容请留言&#xff08;不喜勿喷&#xff09; 本文为追加文章&#xff0c;后期慢慢追加 by 2023年10月 网络安全审计概念 等级保护网络安全审计是指对涉及国家安全、重要利益或关键信息基础设施…

FPGA/SoC控制机械臂

FPGA/SoC控制机械臂 机器人技术处于工业 4.0、人工智能和边缘革命的前沿。让我们看看如何创建 FPGA 控制的机器人手臂。 介绍 机器人技术与人工智能和机器学习一起处于工业 4.0 和边缘革命的最前沿。 因此&#xff0c;我认为创建一个基础机器人手臂项目会很有趣&#xff0c;我们…

听GPT 讲Rust源代码--library/std(3)

rust标准库std中的src目录主要包含以下内容和模块: alloc:内存分配相关函数,比如alloc::boxed::Box、alloc::string::String等。 ascii:ASCII相关工具函数。 char:字符相关类型和函数,如Char、char等。 cmp:比较相关trait和函数,如Ord、Eq、PartialOrd等。 env:环境变量相关功能…

什么是React中的有状态组件(stateful component)和无状态组件(stateless component)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

微信小程序如何跳转页面

1.wx.navigateTo&#xff1a;用于跳转到其他页面&#xff0c;并保留当前页面。通过该 API 跳转后&#xff0c;可以通过返回按钮回到原页面。 wx.navigateTo({url: /pages/otherPage/otherPage })2.wx.redirectTo&#xff1a;用于跳转到其他页面&#xff0c;并关闭当前页面。通…

探索SOCKS5与SK5代理在现代网络环境中的应用

随着互联网技术的飞速发展&#xff0c;网络安全成为了不容忽视的重要议题。其中&#xff0c;网络代理技术作为一种重要的网络安全手段&#xff0c;以其独特的功能和优势在网络安全领域占据了重要的位置。本文将探讨两种常见的代理技术&#xff1a;SOCKS5代理和SK5代理&#xff…

Linux中关于glibc包导致的服务器死机或者linux命令无法使用的情况

glibc是gnu发布的libc库&#xff0c;即c运行库。glibc是linux系统中最底层的api&#xff0c;几乎其它任何运行库都会依赖于glibc。glibc除了封装linux操作系统所提供的系统服务外&#xff0c;它本身也提供了许多其它一些必要功能服务的实现。由于 glibc 囊括了几乎所有的 UNIX …

量子计算与量子密码(入门级)

量子计算与量子密码 写在最前面一些可能带来的有趣的知识和潜在的收获 1、Introduction导言四个特性不确定性&#xff08;自由意志论&#xff09;Indeterminism不确定性Uncertainty叠加原理(线性)superposition (linearity)纠缠entanglement 虚数的常见基本运算欧拉公式&#x…

本地新建项目如何推到码云上去

1.先在码云上建立一个空仓库&#xff0c;正常步骤就行。建立完成有readme.md. 2.然后本地建立项目文件&#xff0c;正常脚手架搭建VUE\REACT等。记得要项目git init一下。 3.本地改好的内容commit 一下。 4.本地文件与远端仓库建立连接。git remote add origin https://gite…

基于C/C++的UG二次开发流程

文章目录 基于C/C的UG二次开发流程1 环境搭建1.1 新建工程1.2 项目属性设置1.3 添加入口函数并生成dll文件1.4 执行程序1.5 ufsta入口1.5.1 创建程序部署目录结构1.5.2 创建菜单文件1.5.3 设置系统环境变量1.5.4 制作对话框1.5.5 创建代码1.5.6 部署和执行 基于C/C的UG二次开发…

hypercube背景设置为白色,绘制高光谱3D立方体

import scipy pip install wxpython PyOpenGL和Spectral需要本地安装 可参考链接https://blog.csdn.net/qq_43204333/article/details/119837870 参考&#xff1a;https://blog.csdn.net/Tiandailan/article/details/132719745?spm1001.2014.3001.5506Mouse Functions:left-cl…