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

【java基础】泛型程序设计基础

文章目录

  • 泛型是什么
  • 自定义泛型类
  • 自定义泛型方法
  • 类型变量的限定
  • 总结

泛型是什么

泛型类和泛型方法有类型参数,这使得它们可以准确地描述用特定类型实例化时会发生什么。在没有泛型类之前,程序员必须使用Objct编写适用于多种类型的代码。这很烦琐,也很不安全。

随着泛型的引入,Java有了一个表述能力很强的类型系统,允许设计者详细地描述变量和方法的类型要如何变化。

泛型程序设计(generic programming)意味着编写的代码可以对多种不同类型的对象重用。

下面的代码就是没有使用泛型的集合

        // 该集合我想要存放int类型的数据List list = new ArrayList();list.add(100); // 加入intlist.add("hello"); // 放入字符串list.add(true); // 放入布尔类型for (int i = 0; i < list.size(); i++) {Object o = list.get(i); // 获取到的值是Objectint k = (Integer) o; // 强制转换System.out.println(k);}

可以发现上面的代码在集合中什么都能放入,并没有进行类型检查。而且在获取集合元素的时候返回的是Object,我们还要进行强转。运行看看一下,结果如下

在这里插入图片描述

可以发现报错了,这就是因为在集合里面存放了其他类型的数据。集合不使用泛型那么就是存储的Object数据,我们将其转换为Integer所以就出现了ClassCastException。现在就已经可以发现java的弊端了,没有一个参数检查机制,代码极不安全,泛型就是用来弥补这点的。看下面泛型代码。

        List<Integer> list = new ArrayList<>();list.add(100);// list.add("hello") // 类型检查,编译都不能通过// list.add(true) // 编译不能通过for (int i = 0; i < list.size(); i++) {Integer k = list.get(i); // 返回的直接就是IntegerSystem.out.println(k);}

我们可以在<>里面指定要存储的元素类型,这就是泛型,使用泛型后在往集合添加元素的时候就会进行检查,如果不是指定的元素,那么就会出现编译错误,程序编译都不能通过。使用泛型后,集合返回的就直接是指定的类型,也就不需要强转类型转换了。

通过上面的代码,大家应该初步体会到了泛型的好处和强大,下面就来学习如何自定义泛型类和泛型方法

自定义泛型类

泛型类就是有一个或多个类型变量的类。下面我就通过MyTool这个类来进行说明

public class MyTool<T> {private T info;public MyTool(T info) {this.info = info;}public T getInfo() {return info;}
}

上面的MyTool这个类就是一个泛型类,在这个类中引入了一个类型变量T,用尖括号(<>)括起来的,放在类名后面。这个T就是我们在创建对象的时候指定的。

MyTool<String> myTool = new MyTool<>("这是自定义泛型类");

我们在尖括号(<>)里面写的类型就会成为T的类型,这里<>里面写的类型为String,那么T就是代表String。

对于 new MyTool<>(“这是自定义泛型类”) 这部分代码,我们在构造器中传入了一个字符串,原因就是T代表的是字符串,而我们的构造器中要传入的内容就是T,也就是字符串,没有问题。

对于在上面的MyTool类,由于我们指定的T为String,所以可以将其理解为就是一个普通类,如下

public class MyTool {private String info;public MyTool(String info) {this.info = info;}public String getInfo() {return info;}
}

现在,对于泛型类的基本使用基本就说完了,我们自定义泛型类就是在类后面加上<>,在这里面写上类型变量,然后再类中使用这个类型变量即可。对于类型变量,我们一般都是使用大写字母,而且很简短,在Java库使用变量E表示集合的元素类型,K和V分别表示表的键和值的类型。T(必要时还可以用相邻的字母U和S)表示“任意类型”。
注意:对于类型变量并不是一定为一个大小字母,只不过是约定俗成罢了,例如,下面代码也是正确的

public class TypeParameter<AAAAA> {private AAAAA aaaaa;
}

但是还是建议大家就写为一个大写字母,遵顼java规范。

对于泛型类,我们在<>里面可以写上多个类型变量,使用逗号分隔,例如下面代码

public class MulTypeParam<K,V> {
}

这样定义以后,我们在使用这个对象就要在<>里面传入2个变量

MulTypeParam<Integer, String> typeParam = new MulTypeParam<>();

这样写的话,那么K就代表Integer类型,V就代表String类型

自定义泛型方法

上面说的是自定义泛型类,现在来讲一下泛型方法。下面就是一个简单示例

public class SimpleGenericMethod {public static <T> T getMiddleInfo(T... ts) {int index = ts.length / 2;return ts[index];}
}

对于泛型方法,我们并不需要放在泛型类中,放在普通类中也没有问题。对于泛型方法,我们将类型变量放在<>中,<>放在返回值前面,修饰符后面。

上面的方法就是接收T类型的参数,然后返回一个T。下面就是对泛型方法的调用

String middleInfo = SimpleGenericMethod.<String>getMiddleInfo("java", "python", "c", "c++", "php");

可以发现在泛型方法中,我们是在方法前面添加了一个<>,然后指定了类型。但是对于大多数情况下,<>都可以省略,编译器会根据传入的参数推断出类型。
在几乎所有情况下,泛型方法的类型推导都可以正常工作。下面写法就是省略<>写法

String middleInfo = SimpleGenericMethod.getMiddleInfo("java", "python", "c", "c++", "php");

类型推导的原则就是寻找参数的公共父类。

对于泛型方法,我们也可以在<>里面定义多个类型变量

    public static <X, Y> Y towTypeParam(X x, Y y) {return y;}

上面代码就表示传入一个X类型的变量和一个Y类型的变量,然后返回一个Y类型变量。

类型变量的限定

在很多的情况下,我们使用泛型时,并不是上面类型的参数都能传入,而是有所现在,比如是某个类的子类,或者必须实现某个接口。下面就来说明如何完成这些对泛型的限制。

先来看一个例子

public interface Eat {void eat();
}
public class TypeParamRestrict {public static <T> void eats(T... ts) {for (T t : ts) {((Eat) t).eat();}}
}

看看上面这个eats有上面问题呢?可以发现,我们并没有检查T类型的参数,T不一定是一个实现接口的Eat的对象,这样调用就会出错,所以,我们应该对T进行限制,写法如下

public class TypeParamRestrict {public static <T extends Eat> void eats(T... ts) {for (T t : ts) {t.eat();}}
}

T extends Eat就表示传入的类型必须是为Eat,或者Eat的子类。这里使用extends可能有人很疑惑,Eat不是接口吗?为什么是使用extends,事实上,这里选择extends是为了更接近子类的概念,对于接口和类都是使用extends。使用了限定符后,就不需要进行类型转换了,T已经是Eat的子类,所以可以直接掉用eat方法。

上面这样写了以后,再调用eats这个方法,参数就必须是实现Eat接口的类。

对于一个类型变量,我们还可以有多个限定,例如下面代码

<T extends Eat & Serializable>

使用&就表示必须且的意思,表示T要同时实现Eat和Serializable接口。
注意:对于限定,可以有多个接口,但是只能有一个是类,而且必须写为第一个限定。为什么只能有一个限定类,因为java是单继承的。类型变量不可能同时实现多个类

总结

泛型程序设计(generic programming)就是意味着编写的代码可以对多种不同类型的对象重用。

关于泛型的更多知识,参考以下内容

泛型程序设计基础
类型擦除、桥方法、泛型代码和虚拟机
泛型的限制及其继承规则
泛型的通配符(extends,super,?)

相关文章:

【java基础】泛型程序设计基础

文章目录泛型是什么自定义泛型类自定义泛型方法类型变量的限定总结泛型是什么 泛型类和泛型方法有类型参数&#xff0c;这使得它们可以准确地描述用特定类型实例化时会发生什么。在没有泛型类之前&#xff0c;程序员必须使用Objct编写适用于多种类型的代码。这很烦琐&#xff…...

【省选模拟测试23 T1直径】更好的做法

题目大意和普通做法 省选模拟测试23 T1直径 题解 对于上文中有三个儿子的根节点的树&#xff0c;其直径数量为abbccaabbccaabbcca。那么对于上文中有nnn个儿子的根节点的树&#xff0c;其直径数量为多少呢&#xff1f; 每个儿子所在子树中的点与其他儿子所在子树中的点都能组…...

SpringCloud基础(3)-微服务远程调用

SpringCloud基础1. 微服务的远程调用2. Eureka注册中心1. 搭建Eureka服务注册中心1. 微服务的远程调用 服务提供者&#xff1a;一次业务中被其它服务调用的一方&#xff1b; 服务消费者&#xff1a;一次业务中调用其它服务的一方&#xff1b; 2. Eureka注册中心 记录所有服务…...

10.单点登录原理及JWT实现

单点登录原理及JWT实现 一、单点登录效果 首先我们看通过一个具体的案例来加深对单点登录的理解。案例地址&#xff1a;https://gitee.com/xuxueli0323/xxl-sso?_fromgitee_search 把案例代码直接导入到IDEA中 然后分别修改下server和samples中的配置信息 在host文件中配置 …...

图表控件LightningChart.NET 系列教程(十一):LightningChart 组件——添加至 Blend WPF 项目

LightningChart.NET 是一款高性能 WPF 和 Winforms 图表,可以实时可视化多达1万亿个数据点。可有效利用CPU和内存资源&#xff0c;实时监控数据流。同时&#xff0c;LightningChart使用突破性创新技术&#xff0c;以实时优化为前提&#xff0c;大大提升了实时渲染的效率和效果&…...

libGDX:灯光效果实现一(实现一个点光源)

国内的libGDX文章很少&#xff0c;特别是libGDX实现灯光效果&#xff0c;所以就开始总结灯光效果的实现 绿色的框 是为了方便看到Body位置&#xff0c;使用Box2DDebugRenderer渲染的 工欲善其事&#xff0c;必先利其器&#xff0c;工具集合 gdx-setup.jar 1. 从libGDX官网下载…...

Java生态/Redis中如何使用Lua脚本

文章目录一、安装LUA1&#xff09;简单使用二、lua语法简介1、注释1&#xff09;单行注释2&#xff09;多行注释2、关键字3、变量1&#xff09;全局变量2&#xff09;局部变量4、数据类型1&#xff09;Lua数组2&#xff09;字符串操作5、if-else6、循环1&#xff09;for循环1&g…...

网络编程 socket 编程(一)

1. C/S 架构 C/S 架构即客户端/服务端架构&#xff0c;B/S 架构&#xff08;浏览器与服务端&#xff09;也是 C/S 架构的一种。 C/S 架构与 socket 的关系&#xff1a;学习 socket 可以完成 C/S 架构的开发。 2. osi 七层 一个完整的计算机系统由硬件、操作系统以及应用软件…...

【SpringCloud】SpringCloud教程之Nacos实战(一)

目录Nacos是什么&#xff1f;一.Nacos下载二.安装Nacos三.Nacos原理四.Nacos快速入门五.Nacos服务多级存储模式六.Nacos根据集群设置负载均衡1.根据同集群优先访问2.根据权重配置负载均衡七.Nacos的环境隔离八.Nacos和Eureka的区别前提&#xff1a;以订单服务和用户服务为例&am…...

高通Android 12/13 默认应用程序授予权限

1、一提到权限很多Android开发者都会想到 比如拨打电话 读取手机通讯录 定位 这些都是需要申请权限&#xff0c;Google Android 6.0之后&#xff08;sdk 23&#xff09; 需要app动态申请权限 或者权限组 2、我这里打个比方 比如需要在fm应用 默认打开mic权限 3、我们需要知道…...

代码随想录|day6|哈希表篇-- 242.有效的字母异位词 、349. 两个数组的交集 、202. 快乐数、1. 两数之和

总链接https://docs.qq.com/doc/DUEtFSGdreWRuR2p4?u329948d2f0044f34b7cbe72503f0b572 242.有效的字母异位词 链接&#xff1a;代码随想录 class Solution { public:bool isAnagram(string s, string t) {//两种做法&#xff0c;一种是int f[26]的数组,一种是map /*第一种&a…...

k8s学习之路 | Day20 k8s 工作负载 Deployment(下)

文章目录3. HPA 动态扩缩容3.1 HPA3.2 安装 metrics-server3.3 验证指标收集3.4 扩缩容的实现3.5 增加负载3.6 降低负载3.7 更多的度量指标4. 金丝雀部署4.1 蓝绿部署4.2 金丝雀部署4.3 金丝雀部署的实现5. Deployment 状态与排查5.1 进行中的 Deployment5.2 完成的 Deployment…...

考研复试——操作系统

文章目录操作系统1. 操作系统的特征&#xff1a;2. 进程与线程的关系以及区别3. 简述进程和程序的区别4. 进程的常见状态&#xff1f;以及各种状态之间的转换条件&#xff1f;5. 进程的调度算法有哪些&#xff1f;6. 什么是死锁&#xff1f;产生条件&#xff1f;如何避免死锁&a…...

Java ~ Collection/Executor ~ LinkedBlockingDeque【源码】

一 LinkedBlockingDeque&#xff08;链接阻塞双端队列&#xff09;类源码及机制详解 类 LinkedBlockingDeque&#xff08;链接阻塞双端队列&#xff09;类&#xff08;下文简称链接阻塞双端队列&#xff09;是BlockingDeqeue&#xff08;阻塞双端队列&#xff09;接口的唯一实现…...

【前缀和】截断数组、K倍区间、激光炸弹

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…...

函数编程:强大的 Stream API

函数编程&#xff1a;强大的 Stream API 每博一文案 只要有人的地方&#xff0c;世界就不会是冰冷的&#xff0c;我们可以平凡&#xff0c;但绝对不可以平庸。—————— 《平凡的世界》人活着&#xff0c;就得随时准备经受磨难。他已经看过一些书&#xff0c;知道不论是普通…...

企业架构图之业务架构图

在TOGAF的世界里面&#xff0c;所有的架构思想都可以通过下面三种类型的图形进行表示。 目录&#xff08;Catalogs&#xff09;矩阵&#xff08;Matrix&#xff09;图 &#xff08;Diagram&#xff09; 其架构图的本质就是用来进行沟通交流&#xff0c;通过架构图和业务团队进…...

监控易网络管理:网络流量分析

1、什么是网络流量分析2、网络流量分析的作用3、为什么要用网络流量分析功能&#xff0c;如何开启什么是网络流量分析简单的来说&#xff0c;网络流量分析就是捕捉网络中流动的数据包&#xff0c;并通过查看包内部数据以及进行相关的协议、流量、分析、统计等&#xff0c;协助发…...

RHCSA-文件内容显示(3.6)

查看命令 cat&#xff1a;显示文件内容 cat -n&#xff1a;显示文件内容的同时显示编号 tac&#xff1a;倒叙查看 head 文件名 &#xff08;默认显示前10行&#xff09;&#xff1a;显示前10行 tail&#xff1a;显示末尾行数信息 more&#xff1a;查看文件信息&#xff0c;从头…...

Qt多线程文件查找器

⭐️我叫恒心,一名喜欢书写博客的研究生在读生。 原创不易~转载麻烦注明出处,并告知作者,谢谢!!! 这是一篇近期会不断更新的博客欧~~~ 有什么问题的小伙伴 欢迎留言提问欧。 Qt多线程文件查找器 前言 最近在实现一些代码功能的时候,需要找一些多线程样例来学习,于是就…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

ubuntu22.04有线网络无法连接,图标也没了

今天突然无法有线网络无法连接任何设备&#xff0c;并且图标都没了 错误案例 往上一顿搜索&#xff0c;试了很多博客都不行&#xff0c;比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动&#xff0c;重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...