当前位置: 首页 > news >正文

泛型详解.

1 泛型的引入
问题:我们之前实现过的顺序表,只能保存 int 类型的元素,如果现在需要保存 指向 Person 类型对象的引用的顺序表,请问应该如何解决?如果又需要保存指向 Book 对象类型的引用呢?

之前写的顺序表代码示例:

import java.util.Arrays;public class MyArrayList {private int[] elem;private int usedSize;private static int capacity = 10;public MyArrayList() {this.elem = new int[capacity];}public boolean isFull() {if (this.usedSize == capacity) {return true;}return false;}public void add(int pos, int data) {if (pos < 0 || pos > this.usedSize) {System.out.println("pos位置不合法");return;}if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * capacity);capacity *= 2;}for (int i = this.usedSize - 1; i >= pos; i--) {this.elem[i + 1] = this.elem[i];}this.elem[pos] = data;this.usedSize++;}public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");}System.out.println();}public boolean isEmpty() {if (this.usedSize == 0) {return true;}return false;}public boolean contains(int toFind) {if (isEmpty()) {return false;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return true;}}return false;}public int search(int toFind) {if (isEmpty()) {return -1;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return i;}}return -1;}public int getPos(int pos) {if (isEmpty()) {throw new RuntimeException("顺序表为空!");}if (pos < 0 || pos >= this.usedSize) {throw new RuntimeException("pos不合法");}return this.elem[pos];}public int size() {return this.usedSize;}public void setPos(int pos, int value) {if (pos < 0 || pos >= this.usedSize) {System.out.println("pos位置不合法!");return;}this.elem[pos] = value;}public void remove(int toRemove) {if (isEmpty()) {return;}int index = search(toRemove);if (index == -1) {System.out.println("没有你要删除的数字!");}for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i + 1];}this.usedSize--;}public void clear() {for (int i = 0; i < this.usedSize; i++) {this.elem[i] = 0;}this.usedSize = 0;}public static void main(String[] args) {MyArrayList myArrayList = new MyArrayList();myArrayList.add(0, 1);myArrayList.add(1, 2);myArrayList.add(2, 3);myArrayList.add(3, 4);System.out.println(myArrayList.size());myArrayList.display();System.out.println(myArrayList.contains(3));System.out.println(myArrayList.contains(2));System.out.println(myArrayList.search(5));System.out.println(myArrayList.search(2));System.out.println(myArrayList.getPos(0));System.out.println(myArrayList.usedSize);myArrayList.display();myArrayList.remove(1);myArrayList.remove(2);myArrayList.display();myArrayList.remove(4);myArrayList.display();myArrayList.clear();System.out.println("==============");myArrayList.display();}
}
  • 首先,我们在学习多态过程中已知一个前提,父类的引用可以指向子类的对象。
  • 其次,我们也已知 Object 是 java 中所有类的祖先类
     

那么,要解决上述问题,我们很自然的想到一个解决办法,将我们的顺序表的元素类型定义成 Object 类型,这样我们的 Object 类型的引用可以指向 Person 类型的对象或者指向 Book 类型的对象了。

因为代码改动较多,现在指出主要代码:

这样,我们可以就可以很自由的存储指向任意类型对象的引用到我们的顺序表了。
 

改编后的代码: 

 

package test1;import java.util.Arrays;public class MyArrayList {private Object[] elem;private int usedSize;private static int capacity = 10;public MyArrayList() {this.elem = new Object[capacity];}public boolean isFull() {if (this.usedSize == capacity) {return true;}return false;}public void add(int pos, Object data) {if (pos < 0 || pos > this.usedSize) {System.out.println("pos位置不合法");return;}if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * capacity);capacity *= 2;}for (int i = this.usedSize - 1; i >= pos; i--) {this.elem[i + 1] = this.elem[i];}this.elem[pos] = data;this.usedSize++;}public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");System.out.println();}System.out.println();}public boolean isEmpty() {if (this.usedSize == 0) {return true;}return false;}public boolean contains(Object toFind) {if (isEmpty()) {return false;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return true;}}return false;}public int search(Object toFind) {if (isEmpty()) {return -1;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return i;}}return -1;}public Object getPos(int pos) {if (isEmpty()) {throw new RuntimeException("顺序表为空!");}if (pos < 0 || pos >= this.usedSize) {throw new RuntimeException("pos不合法");}return this.elem[pos];}public int size() {return this.usedSize;}public void setPos(int pos, int value) {if (pos < 0 || pos >= this.usedSize) {System.out.println("pos位置不合法!");return;}this.elem[pos] = value;}public void remove(int toRemove) {if (isEmpty()) {return;}int index = search(toRemove);if (index == -1) {System.out.println("没有你要删除的数字!");}for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i + 1];}this.usedSize--;}public void clear() {for (int i = 0; i < this.usedSize; i++) {this.elem[i] = 0;}this.usedSize = 0;}public static void main(String[] args) {MyArrayList books = new MyArrayList();for (int i = 0; i < 10; i++) {books.add(i,new Book("三国演义", "罗贯中", 15));}books.display();
//        MyArrayList myArrayList = new MyArrayList();
//        myArrayList.add(0, 1);
//        myArrayList.add(1, 2);
//        myArrayList.add(2, 3);
//        myArrayList.add(3, 4);
//        System.out.println(myArrayList.size());
//        myArrayList.display();
//        System.out.println(myArrayList.contains(3));
//        System.out.println(myArrayList.contains(2));
//        System.out.println(myArrayList.search(5));
//        System.out.println(myArrayList.search(2));
//        System.out.println(myArrayList.getPos(0));
//        System.out.println(myArrayList.usedSize);
//        myArrayList.display();
//        myArrayList.remove(1);
//        myArrayList.remove(2);
//        myArrayList.display();
//        myArrayList.remove(4);
//        myArrayList.display();
//        myArrayList.clear();
//        System.out.println("==============");
//        myArrayList.display();}
}


遗留问题:现在的 MyArrayList 虽然可以做到添加任意类型的引用到其中了,但遇到以下代码就会产生问题。

写一个Person类:

 接下来我称之为牛马操作:

编译竟然正确,没有报红,我们运行一下看看:

 

运行时会抛出了异常
 

提示:问题暴露的越早,影响越小。编译期间的问题只会让开发者感觉到,运行期间的错误会让所有的软件使用者承受错误风险。

所以我们需要一种机制,可以 1. 增加编译期间的类型检查 2. 取消类型转换的使用 泛型就此诞生!
 

2.泛型的分类

  • 1. 泛型类
  • 2. 泛型方法

3 泛型类的定义的简单演示


 注意: 泛型类可以一次有多个类型变量,用逗号分割。
 

4 泛型背后作用时期和背后的简单原理

  • 1. 泛型是作用在编译期间的一种机制,即运行期间没有泛型的概念。
  • 2. 泛型代码在运行期间,就是我们上面提到的,利用 Object 达到的效果(这里不是很准确,以后会做说明)。
     

5 泛型类的使用


 

通过以上代码,我们可以看到泛型类的一个使用方式:只需要在所有类型后边跟尖括号,并且尖括号内是真正的类型,即 E 可以看作的最后的类型。
 

看具体代码:

package test1;import java.util.Arrays;public class MyArrayList<E> {private Object[] elem;private int usedSize;private static int capacity = 10;private E e;public MyArrayList() {this.elem = new Object[capacity];this.e = e;}public boolean isFull() {if (this.usedSize == capacity) {return true;}return false;}public void add(int pos, E data) {if (pos < 0 || pos > this.usedSize) {System.out.println("pos位置不合法");return;}if (isFull()) {this.elem = Arrays.copyOf(this.elem, 2 * capacity);capacity *= 2;}for (int i = this.usedSize - 1; i >= pos; i--) {this.elem[i + 1] = this.elem[i];}this.elem[pos] = data;this.usedSize++;}public void display() {for (int i = 0; i < this.usedSize; i++) {System.out.print(this.elem[i] + " ");System.out.println();}System.out.println();}public boolean isEmpty() {if (this.usedSize == 0) {return true;}return false;}public boolean contains(E toFind) {if (isEmpty()) {return false;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return true;}}return false;}public int search(E toFind) {if (isEmpty()) {return -1;}for (int i = 0; i < this.usedSize; i++) {if (this.elem[i] == toFind) {return i;}}return -1;}public Object getPos(int pos) {if (isEmpty()) {throw new RuntimeException("顺序表为空!");}if (pos < 0 || pos >= this.usedSize) {throw new RuntimeException("pos不合法");}return this.elem[pos];}public int size() {return this.usedSize;}public void setPos(int pos, int value) {if (pos < 0 || pos >= this.usedSize) {System.out.println("pos位置不合法!");return;}this.elem[pos] = value;}public void remove(E toRemove) {if (isEmpty()) {return;}int index = search(toRemove);if (index == -1) {System.out.println("没有你要删除的数字!");}for (int i = index; i < this.usedSize - 1; i++) {this.elem[i] = this.elem[i + 1];}this.usedSize--;}public void clear() {for (int i = 0; i < this.usedSize; i++) {this.elem[i] = 0;}this.usedSize = 0;}public static void main(String[] args) {MyArrayList<Book> books = new MyArrayList<Book>();books.add(0, new Book("红楼梦", "曹雪芹", 18));books.add(2, new Person("lisi", "lll"));//        Book book1 = new Book("红楼梦", "曹雪芹", 18);
//        for (int i = 0; i < 10; i++) {
//            if (i == 0) {
//                books.add(i, book1);
//            } else {
//                books.add(i, new Book("三国演义", "罗贯中", 15));
//            }
//        }
//        books.display();
//        Person person = (Person) books.getPos(0);
//        MyArrayList myArrayList = new MyArrayList();
//        myArrayList.add(0, 1);
//        myArrayList.add(1, 2);
//        myArrayList.add(2, 3);
//        myArrayList.add(3, 4);
//        System.out.println(myArrayList.size());
//        myArrayList.display();
//        System.out.println(myArrayList.contains(3));
//        System.out.println(myArrayList.contains(2));
//        System.out.println(myArrayList.search(5));
//        System.out.println(myArrayList.search(2));
//        System.out.println(myArrayList.getPos(0));
//        System.out.println(myArrayList.usedSize);
//        myArrayList.display();
//        myArrayList.remove(1);
//        myArrayList.remove(2);
//        myArrayList.display();
//        myArrayList.remove(4);
//        myArrayList.display();
//        myArrayList.clear();
//        System.out.println("==============");
//        myArrayList.display();}
}

 

那么现在就会出现编译错误 ,这就是泛型的作用!

注意: Book 只能想象成 E 的类型,但实际上 E 的类型还是 Object。
 

6 泛型总结

  • 1. 泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型检查。
  • 2. 泛型利用的是 Object 是所有类的祖先类,并且父类的引用可以指向子类对象的特定而工作。
  • 3. 泛型是一种编译期间的机制,即 MyArrayList<Person> 和 MyArrayList<Book> 在运行期间是一个类型。
  • 4. 泛型是 java 中的一种合法语法,标志就是尖括号 <>
     

相关文章:

泛型详解.

1 泛型的引入 问题&#xff1a;我们之前实现过的顺序表&#xff0c;只能保存 int 类型的元素&#xff0c;如果现在需要保存 指向 Person 类型对象的引用的顺序表&#xff0c;请问应该如何解决&#xff1f;如果又需要保存指向 Book 对象类型的引用呢&#xff1f; 之前写的顺序表…...

Vue 3.0 响应性 深入响应性原理 【Vue3 从零开始】

现在是时候深入了&#xff01;Vue 最独特的特性之一&#xff0c;是其非侵入性的响应性系统。数据模型是被代理的 JavaScript 对象。而当你修改它们时&#xff0c;视图会进行更新。这让状态管理非常简单直观&#xff0c;不过理解其工作原理同样重要&#xff0c;这样你可以避开一…...

升级 vue3 常见问题总汇

Ⅰ、前言 虽然 vue3 是没有删除 vue2 的 选项式 API &#xff0c; 但是我们升级vue3 还是需要修改很多问题的下面来看看我们升级常见的一些问题 &#x1f447; 文章目录Ⅰ、前言Ⅱ、解决兼容问题1、路由的创建方式2、路由的方法变化3、升级 vuex 到 4.x4、作用域 插槽语法修改…...

汽车 Automotive > T-BOX GNSS高精定位测试相关知识

参考&#xff1a;https://en.wikipedia.org/wiki/Global_Positioning_SystemGPS和GNSS的关系GPS&#xff08;Global Positioning System&#xff09;&#xff0c;全球定位系统是美国军民两用的导航定位卫星系统&#xff0c;GPS包含双频信号&#xff0c;频点L1、L2和L5GNSS&…...

大数据面试核心101问【大厂超级喜欢这些题】

之前出过《史上最全的大数据开发八股文》这篇文章&#xff0c;同学们都觉得还不错&#xff0c;但是有些同学觉得那个背起来还是有些吃力&#xff0c;于是我再次回顾了自己之前面试所有大厂的一些面试题以及牛客上面的一些面经&#xff0c;然后总结了频率问的最高的101问&#x…...

代码随想录算法训练营第四十八天 | leetcode 121. 买卖股票的最佳时机,122.买卖股票的最佳时机II

代码随想录算法训练营第四十八天 | leetcode 121. 买卖股票的最佳时机&#xff0c;122.买卖股票的最佳时机II121. 买卖股票的最佳时机122.买卖股票的最佳时机II121. 买卖股票的最佳时机 题目&#xff1a; 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支…...

RAD 11.3 delphi和C++改进后新增、废弃及优化的功能

RAD 11.3 delphi和C改进后新增和废弃的功能 目录 RAD 11.3 delphi和C改进后新增和废弃的功能 一、版本RAD 11.3 delphi和C改进后新增功能 1、官方视频位置&#xff1a; 2、官方文档的链接位置&#xff1a; 二、版本RAD 11.3 delphi和C改进后废弃的功能 2.1、编译器不再使…...

【C++】引用

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、引用1.1 引用概念1.2 引用特性…...

LPNet for Image Derain

Lightweight Pyramid Networks for Image Deraining前置知识高斯-拉普拉斯金字塔图像中的高频信息和低频信息为什么高斯-拉普拉斯金字塔可以实现去雨&#xff1f;可能性分析网络结构整体结构&#xff1a;子网结构&#xff1a;递归块结构&#xff1a;后续补充代码 前置知识 这…...

【NLP相关】基于现有的预训练模型使用领域语料二次预训练

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…...

使用git进行项目管理--git使用及其常用命令

使用git进行项目管理 文章目录 使用git进行项目管理git使用1.添加用户名字2.添加用户邮箱3.git初始化4.add5.commit6.添加到gitee仓库7.推送到gitee8.切换版本git常用命令git add把指定的文件添加到暂存区中添加所有修改、已删除的文件到暂存区中添加所有修改、已删除、新增的文…...

Mybatis_CRUD使用

目录1 Mybatis简介环境说明:预备知识:1.1 定义1.2 持久化为什么需要持久化服务呢&#xff1f;1.3 持久层1.4 为什么需要Mybatis2 依赖配置3 CRUDnamespaceselect &#xff08;查询用户数据&#xff09;※传值方式&#xff1a;于方法中传值使用Map传值insert &#xff08;插入用…...

JVM的过程内分析和过程间分析有什么区别?

问&#xff1a; 目前所有常见的Java虚拟机对过程间分析的支持都相 当有限&#xff0c;要么借助大规模的方法内联来打通方法间的隔阂&#xff0c;以过程内分析&#xff08;Intra-Procedural Analysis&#xff0c; 只考虑过程内部语句&#xff0c;不考虑过程调用的分析&#xff…...

LearnDash测验报告如何帮助改进您的课程

某一个场景。Pennywell 大学有一门课程“Introduction to Linear Algebra”。上学期进行了两次测验。20% 的学生在第一次测验中不及格&#xff0c;而 80% 在第二次测验中不及格。在进一步评估中&#xff0c;观察到第一次测验不及格的学生在第二次测验中也不及格。在第二次测验中…...

如何通过Java将Word转换为PDF

Word是我们日常编辑文档内容时十分常用的一种文档格式。但相比之下&#xff0c;PDF文档的格式、布局更为固定&#xff0c;不易被更改。在保存或传输较为重要的文档内容时&#xff0c;PDF文档格式也时很多人的不二选择。很多时候我们都会遇到需要将Word转换为PDF的情况。下面我就…...

DOM型XSS

DOM型XSSDOM是什么DOM型XSSDOM型XSS实操DOM是什么 DOM就是Document。 文档是由节点构成的集合&#xff0c;在DOM里存在许多不同类型的节点&#xff0c;主要有&#xff1a;元素节点、文本节点&#xff0c;属性节点。 元素节点&#xff1a;好比< body >< p >< h …...

04-项目立项:项目方案、可行性分析、产品规划、立项评审

文章目录4.1 项目方案立项阶段4.2 可行性分析4.3 产品规划4.4 立项评审4.4.1 立项说明书的主要内容4.4.2 立项评审流程章节总结4.1 项目方案 学习目标&#xff1a; 能够输出产品项目方案 项目开发设计流程的主要阶段&#xff1a; 立项阶段 → 设计阶段 → 开发阶段 → 测试阶…...

数据分享|NPP VIIRS夜间灯光数据(2012-2020逐月)

2011年10月美国的“索米”国家极轨卫星伙伴卫星(Suomi National Polar-orbiting Partnership or Suomi NPP)发射,它搭载的VIIRS传感器上有一个称为DNB(Day Night Band)的波段能够在500米分辨率(比原来的OLS提高6倍)的尺度上对地表开展每天覆盖全球一次的高灵敏度(比OLS提…...

网络概论笔记

概论 网络研究的是节点和边 移动互联到物联网时代&#xff0c;只有有互联网&#xff0c;网络就不会落伍 协议&#xff1a;对等层面的实体固定的通信规则 协议包括&#xff1a;语法&#xff0c;语义&#xff0c;格式&#xff0c;次序&#xff0c;动作 网络是任意连接的 服务…...

软工2023个人作业二——软件案例分析

项目内容这个作业属于哪个课程2023年北航敏捷软件工程这个作业的要求在哪里个人作业-软件案例分析我在这个课程的目标是学习并掌握现代软件开发和项目管理技术&#xff0c;体验敏捷开发工作流程这个作业在哪个具体方面帮助我实现目标从软件工程角度分析比较我们所熟悉的软件&am…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...