Java 基础(1)—泛型简单使用
一、泛型定义及作用
泛型是一种编程机制,允许在编写代码时使用参数化类型,以在编译时实现类型安全。 以下是泛型作用:
-
增强代码可读性和可维护性:通过在代码中使用泛型参数,可以使代码更清晰、更具有可读性和可维护性。
-
提高代码安全性:泛型可以在编译时检查类型,从而防止在运行时出现类型转换错误。
-
增加代码重用性:泛型允许在不同的数据类型上编写通用代码,从而提高代码的重用性。
-
简化代码:使用泛型可以避免重复编写类似的代码,从而简化代码。
总之,泛型是一种强大的编程机制,它可以帮助开发者编写更具可读性、可维护性、安全性和重用性的代码。
Java 泛型在编译期间会执行类型擦除(Type Erasure)。类型擦除是指编译器在编译泛型代码时,会将泛型类型擦除为其原始类型或限定类型,从而在运行时不存在泛型类型。在进行类型擦除时,编译器会将泛型类型参数替换为它们的边界(限定)类型(如果有的话),如果没有指定限定类型,则会将泛型类型参数替换为 Object 类型
例如,一个泛型类定义如下:
public class Box<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}
在编译后,类型擦除会将泛型类型 T 擦除为 Object 类型,生成的字节码如下:
public class Box {private Object content;public void setContent(Object content) {this.content = content;}public Object getContent() {return content;}
}
需要注意的是,尽管在运行时不存在泛型类型,但是在编译期间编译器仍会对泛型类型进行类型检查,从而确保类型安全。
二、泛型使用
1、泛型定义在类上
代码如下:
class CommonUtil {public Object obj;public Object getObj() {return obj;}public void setObj(Object obj) {this.obj = obj;}
}
在使用的时候,代码如下:
public static void main(String[] args) {CommonUtil tool = new CommonUtil<>();tool.setObj(2);Integer val1 = (Integer)tool.getObj();tool.setObj("hello java");String val2 = (String)tool.getObj();}
从上述代码可以看出,在获取值时每次都需要强转,稍不留神就容易发生强转错误。所以能不能通过一种方式避免类型强转呢?答案是:泛型。将泛型定义在类上,就可以避免类型转换。 改进代码如下:
class CommonUtil<T> {public T obj;public T getObj() {return obj;}public void setObj(T obj) {this.obj = obj;}
}
在创建实例时把具体类型传入,代码如下:
public static void main(String[] args) {CommonUtil<Integer> tool = new CommonUtil<>();tool.setObj(2);Integer val1 = tool.getObj();CommonUtil<String> tool = new CommonUtil<>();tool.setObj("hello java");String val2 = tool.getObj();}
2、泛型定义方法上
泛型定义在类上有个不太有好的一点,看下面例子,代码如下:
class CommonUtil<T> {public void show(T obj){System.out.println("obj = " + obj);}
}
代码使用代码如下:
CommonUtil<Integer> tool1 = new CommonUtil<>();tool1.show(value);CommonUtil<String> tool2 = new CommonUtil<>();tool2.show("111");CommonUtil<Person> tool2 = new CommonUtil<>();tool2.show(new Person());
发现没,每次调用 show() 方法,都需要在通过创建实例,因为在创建时可以指定具体使用的参数类型。但是这样创建对象太麻烦,怎么解决,可以将泛型定义在方法上,代码如下:
class CommonUtil {public <W> void show(W obj){System.out.println("obj = " + obj);}
}
使用代码如下:
CommonUtil tool1 = new CommonUtil<>();tool1.show(value);tool1.show("111");tool1.show(new Person());
最后在方法调用时传入具体参数类型,这样就可以避免重复创建对象,做到一个方法重复调用,和 Object 非常类似。包括 static 修饰的静态方法也是一样可以使用。代码如下:
class CommonUtil {public static <W> void show(W obj){System.out.println("obj = " + obj);}
}
使用代码如下:
CommonUtil.show(value);CommonUtil.show("111");CommonUtil.show(new Person());
但是泛型定义在静态方法上还要注意,这个静态方法不能使用类上面的泛型。为什么?因为类是在创建时才会指定具体参数类型,而静态方法是在类实例化之前就已经被加载到 JVM,根本不知道你类在创建实例时传入的是什么具体参数类型。错误示例如下:
class CommonUtil<W> {public static <W> void show(W obj){System.out.println("obj = " + obj);}
}
3、泛型定义在接口上
有时候泛型会定义在接口上,代码如下:
public interface Inter<T> {public void print(T obj);
}
接口上的泛型那么可以在子类中指定、或不指定,子类指定具体类型如下:
public InterImpl implements Inter<String> {// 接口上的方法public void print(String obj){}// 子类独有方法protect void show(Object obj){}
}
在使用时,代码如下:
Inter<String> inter = new InterImpl();inter.print("hello");InterImpl impl = new InterImpl();impl.show(new Object());
或者子类中定义泛型,接口定义具体类型,代码如下:
public InterImpl<W> implements Inter<String> {// 接口上的方法public void print(String obj){}// 子类独有方法protect void show(W obj){}
}
在使用时,代码如下:
Inter<String> inter = new InterImpl();inter.print("hello");InterImpl<Integer> impl = new InterImpl();impl.show(new Integer(10));
子类中也不知道具体类型,那么也可以定义泛型,把子类泛型传给接口,代码如下:
public InterImpl<W> implements Inter<W> {// 接口上的方法public void print(W obj){}// 子类独有方法protect void show(W obj){}
}
在使用时,代码如下:
Inter<String> inter = new InterImpl();inter.print("hello");InterImpl<Integer> impl = new InterImpl();impl.show(new Integer(10));
4、泛型通配符
举个例子,代码如下:
public class FanxinDemo {public static void print(Collection<String> list) {list.forEach(e->{System.out.println("e = " + e);});}public static void main(String[] args) {List<String> list1 = new ArrayList<>();list1.add("a");list1.add("b");list1.add("c");List<Integer> list2 = new ArrayList<>();list2.add(1);list2.add(2);print(list1);}
}
可以发现 print() 方法只能输出参数类型是 String 的,其他的参数都不能,怎么可以做到公用这段代码?这里介绍回个泛型通配符 ?,当你不知道泛型是什么类型是,就可以用这个暂时表示,代码如下:
public class FanxinDemo {public static void print(Collection<?> list) {list.forEach(e->{System.out.println("e = " + e);});}public static void main(String[] args) {List<String> list1 = new ArrayList<>();list1.add("a");list1.add("b");list1.add("c");List<Integer> list2 = new ArrayList<>();list2.add(1);list2.add(2);print(list1);print(list2);}
}
但是假设现在不想让 print() 方法被 Integer 类型参数使用,那么需要怎么做呢?这就需要泛型限定了。
5、泛型限定
泛型限定可以限制参数类型范围,? 这个级别范围太大,不安全,通过 extends、super 关键字来限定范围,但是这两个关键字只能是单继承,所以也是有局限的。限定分为两种:让所有父类可以使用,让所有的子类都可以使用
5.1、让所有父类可以使用
代码如下:
public static void print(Collection<? super Integer> list) {list.forEach(e->{System.out.println("e = " + e);});}
表示让 Integer 所有父类都可以使用 print() 方法。
5.2、让所有子类可以使用
代码如下:
public static void print(Collection<? extends String>> list) {list.forEach(e->{System.out.println("e = " + e);});}
表示让所有的 String 子类可以使用 print() 方法。
相关文章:
Java 基础(1)—泛型简单使用
一、泛型定义及作用 泛型是一种编程机制,允许在编写代码时使用参数化类型,以在编译时实现类型安全。 以下是泛型作用: 增强代码可读性和可维护性:通过在代码中使用泛型参数,可以使代码更清晰、更具有可读性和可维护性…...
内存卡损坏了怎么恢复?
内存卡损坏了怎么恢复?现在我们身边有不少电子设备都是用存储卡来存储数据的。一旦需要方便我们直接导出使用。但这存储的数据也不是一定安全的,当我们将内存卡连接到电脑时,难免会碰到病毒、格式化等提示,在这些情况下,可能会导…...
Mysql使用规范(纯技术和实战建议)
1、事务隔级别: (强制):Repeatable-Read(重复读),且不能在会话操作时临时开启隔离级别。 注: Repeatable-Read(重复读)隔离级别解决不了幻读。 可用 show variables l…...
Netty源码解读-EventLoop(二)
一、简介 NioEventLoop的重要组成:Selector、线程、任务队列,他既会处理io事件,也会处理普通任务和定时任务. 1.下面是Selector,注意有两个哦后面会讲 2.下面的爷爷类提供的Thread变量,其实下面发excutor用的就是这个…...
OSI模型详解
今天,我们详解OSI(Open System Inter-connection Reference Model)模型,来看看工业物联网的网络互联和数据互通。 OSI模型 1984年,国际标准化组织(International Organization for Standardization&#…...
Share Creators完成500万美元融资,以工具化手段帮助企业从数字资产管理中解放
近日,总部位于旧金山湾区的初创公司Share Creators宣布完成了新一轮500万美元的融资,投资方为五源资本和福昕PDF。本轮融资主要用于扩大客户基础,并加速在美国、欧洲和亚洲的业务发展。近几年,企业内容及数字资产管理全球市场正在…...
几个Base64编码工具,也有蹊跷
起因 需求:对一段内容进行base64加密,然后通过url的get请求进行发送到后台,由于加密的内容比较少,base64串也不是很长,我认为此方案可行。 于是找了三个base64编码的在线工具,分别是: 平台1&…...
Python|每日一练|排序|递归|字符串|数组|动态规划|单选记录:以特殊格式处理连续增加的数字|正则表达式匹配|地下城游戏
1、以特殊格式处理连续增加的数字(排序) 贡献者:EricLao 给出一串数字, 程序要把数字按照这样的格式输出,把连续增加的数字用 [x-y] 的形式表示,只显示这一组顺序数字的首位两个数字,不连续增…...
Spring Cloud微服务网关Gateway组件
目录 网关简介 什么是Spring Cloud Gateway Spring Cloud Gateway 功能特征 核心概念 工作原理 Spring Cloud Gateway快速开始 环境搭建 集成Nacos 路由断言工厂(Route Predicate Factories)配置 自定义路由断言工厂 过滤器工厂( …...
cluster nodes(集群节点)
CLUSTER NODES 复制 自3.0.0起可用。 时间复杂度: O(N)其中N是 Cluster 节点的总数 Redis 集群中的每个节点都有其当前集群配置的视图,由已知节点的集合给出,我们与这些节点的连接状态,它们的标志&…...
【Android学习】下载jar慢和gradle慢的情况
目录 问题出现的原因 解决方法 解决Gradle下载问题:手动安装 解决jar包下载慢问题:更改下载源 问题出现的原因 国内访问谷歌被墙导致访问速度慢或者干脆无法下载 解决方法 解决Gradle下载问题:手动安装 访问官网Gradle | Release Candi…...
下一个排列-力扣31-java
一、题目描述整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。例如,arr [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地&…...
前端面试题
1.HTTP request报文结构是怎样的 1.首行是Request-Line包括:请求方法,请求URI,协议版本,CRLF(换行符) 2.首行之后是若干行请求头,包括general-header,request-header或者entity-hea…...
jsp游戏门户网站系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 jsp 游戏门户网站系统 是一套完善的web设计系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql,使…...
Git与IDEA强强联合(HTTPS协议连接)
最近在写项目的时候,在台式机和笔记本之间频繁切换,竟然还是用qq传压缩包,我自己都感觉无语,有git这样强大的版本管理工具,我竟然没想起来。然后也没有相关的博文就想来更新一篇。 那么如何使idea和git强强联合呢&…...
leetcode 第二题:两数相加-C语言实现
题目地址 备注: 不要忘记最后一个进位的可能。可以使用typedef,来简化struct的书写 代码实现: #include<stdio.h> #include<stdlib.h>struct listNode {int val;struct listNode* next; };// 使用typedef typedef struct lis…...
【人工智能】PTP网络时钟服务器在智能驾驶里的重要性
【人工智能】PTP网络时钟服务器在智能驾驶里的重要性 【人工智能】PTP网络时钟服务器在智能驾驶里的重要性 一辆宣称具备L4/L5自动驾驶功能的车辆,如果多个激光雷达之间的时间同步不够精确?如果传感器感知数据通过以太网传输到智驾域控制器的延迟不可控…...
【蓝桥杯集训3】二分专题(3 / 5)
目录 二分模板 1460. 我在哪? - 二分答案 哈希表 1221. 四平方和 - 哈希表 / 二分 1、哈希表 2、二分 自定义排序 1227. 分巧克力 - 113. 特殊排序 - 二分模板 l r >> 1 —— 先 r mid 后 l mid1 —— 寻找左边界 —— 找大于某个数的最小值lr…...
在成都的哪个培训机构学习Java好呢?
自从小课06年进入成都这个IT培训市场以来,短短十几年,招过很多学员,也见证过很多机构的起起落落。心中有万分的感慨,总结下来有这几点分享给大家,在选择培训机构时能看清本质,找到适合自己靠谱的机构学Java…...
传输层重要协议之UDP协议和TCP协议详解
更多关于UDP协议和TCP协议请移步官网:https://www.rfc-editor.org/standards#ISUDP标准协议文档-RFC 768TCP标准协议文档-RFC 793UDP协议详解UDP协议的特点:无连接、不可靠传输、面向数据报和全双工。UDP协议报文结构:关于端口号:…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
