当前位置: 首页 > 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…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

【WebSocket】SpringBoot项目中使用WebSocket

1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖&#xff0c;添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...

TJCTF 2025

还以为是天津的。这个比较容易&#xff0c;虽然绕了点弯&#xff0c;可还是把CP AK了&#xff0c;不过我会的别人也会&#xff0c;还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...

JS红宝书笔记 - 3.3 变量

要定义变量&#xff0c;可以使用var操作符&#xff0c;后跟变量名 ES实现变量初始化&#xff0c;因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符&#xff0c;可以创建一个全局变量 如果需要定义…...

Mac flutter环境搭建

一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...