Java泛型理解

什么是泛型?

我们都知道 Java 中有形参和实参之分,是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数,其本身没有确定的值。在调用函数时,实参将赋值给形参。

而泛型是一种参数化的类型(可以理解为类型形参),它允许在定义类、接口时通过一个「标识」表示类中某个属性的类型或者是某个方法的返回值或参数的类型。这个类型参数将在使用时(例如,继承或实现这个接口、创建对象或调用方法时)确定(即实际传入的类型参数,也称为类型实参)。好处是增强代码的安全性。

以 Java 中的集合为例,如果不指定泛型,那么传入集合中的元素就可以是任意类型的,这就可能带来一些问题,比如我取出集合中的某个元素后,可能要进行「类型转换」,但是如果不指定泛型,那么我是无法知道集合中的元素的什么类型的(默认是 Object 类型),就可能带来 ClassCastException 异常。

泛型的使用场景?

  • 自定义通用返回结果 CommonResult<T> 通过参数 T 可根据具体的返回类型动态指定结果的数据类型
  • DAO 层、自定义的通用泛型方法
  • 比较器(Comparable、Comparator)

泛型的使用方式有哪几种?

泛型一般有三种使用方式:泛型类、泛型接口、泛型方法。

泛型方法的一个例子:

// 创建不同类型的数组:  
Integer[] intArray = {1, 2, 3};  
String[] stringArray = {"hello", "world"};  
printArray(intArray);  
printArray(stringArray);public static <E> void printArray(E[] inputArray) {  for (E element : inputArray) {  System.out.printf("%s ", element);  }  System.out.println();  
}

个人认为使用泛型方法的好处有二:

  1. 允许方法传入多种类型的参数,提高了方法的可扩展性。
  2. 允许方法使用和类不同的泛型参数,比如上面的泛型方法使用的是 E,而该方法所在的类使用的可以是 T。

什么是泛型擦除?为什么要擦除?

泛型擦除就是指 Java 程序在编译期间所有的泛型信息都会被擦除,也就是「类型擦除」。

类型擦除的主要过程如下:1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。2.移除所有的类型参数。

比如编译器会在编译期间将泛型 T 擦除为 Object 类型,或将 T extends xxx 擦除为其限定类型 xxx。

总结:泛型本质上还是「编译时行为」。为了保证引入泛型机制但不创建新的类型,减少 JVM 的运行开销,编译器会通过擦除将泛型类转换为一般类。

举个例子来证明泛型是「编译时行为」:

List<Integer> list = new ArrayList<>();  
list.add(2);  
// 1. 编译期间直接添加与泛型参数类型不同元素会报错,因为有「泛型校验」
list.add("aa");  
// 2. 运行期间通过反射添加却是可以的
Class<? extends List> clazz = list.getClass();  
Method add = clazz.getDeclaredMethod("add", Object.class);  
add.invoke(list, "kl");  
System.out.println(list);

也正是由于泛型擦除的问题,下面的「方法重载会报错」:

public static void test(List<String> list1) {  System.out.println(1);  
}  public static void test(List<Integer> list1) {  System.out.println(1);  
}

因为擦除后大家都是 List 了,默认里面存的就是 Object 类型的元素。

通配符

由于如果泛型类型只能是固定的,在某些场景下使用起来不够灵活。

使用通配符可以解决泛型无法协变的问题。

协变指的就是如果 Child 是 Parent 的子类,那么List<Child> 也应该是List<Parent> 的子类,但是泛型是不支持的。

无界通配符

List<?>List 有区别吗?当然有!

List<?> list 表示 list 是持有某种特定类型的 List,但是不知道具体是哪种类型。因此,我们添加元素进去的时候会报错。

List list 表示 list 是持有的元素的类型是 0bject,因此可以添加任何类型的对象,只不过编译器会有警告信息。

List<?> list = new ArrayList<>( );
list.add("sss");//报错
List list2 = new ArrayList<>();
list2. add("sss");//警告信息

上/下边界通配符

在使用泛型的时候,我们还可以为传入的泛型类型实参进行上下边界的限制,如:类型实参只准传入某种类型的父类或某种类型的子类。

上边界通配符 extends 要求传入的类型实参必须是指定类型或其子类。

举个例子:

// 限制必须是 Person 类或其子类
<? extends Person>

下边界通配符 super 则要求传入的类型实参必须是指定类型或其父类。

// 限制必须是 Person 类或其父类
<? super Person>

使用 <? extends xxx><? super extends xxx> 需要注意的点

G<Father> 和 G<Son> 没有继承关系。

image.png

这块可能不太好理解,具体可以看宋红康老师 JavaSE 的视频。

泛型中的坑

1.当泛型遇到 catch

泛型的类型参数不能用在 Java 异常处理的 catch 语句中。因为异常处理是由 JVM 在运行时刻来进行的。由于类型信息被擦除,JVM 是无法区分两个异常类型MyException<String>MyException<Integer>

2.当泛型类内包含静态变量

public class StaticTest{public static void main(String[] args){GT<Integer> gti = new GT<Integer>();gti.var=1;GT<String> gts = new GT<String>();gts.var=2;System.out.println(gti.var);}
}
class GT<T>{public static int var=0;public void nothing(T x){}
}

以上代码输出结果为:2!

由于经过类型擦除,所有的泛型类实例都关联到同一份字节码上,它们的静态变量是共享的。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

以太网基础学习(四)——IP协议

一 、IP协议概述 IP&#xff08;Internet Protocol&#xff0c;互联网协议&#xff09;是互联网通信的基础协议&#xff0c;它负责将数据包从源地址传输到目的地址。IP协议定义了如何封装数据包&#xff0c;如何寻址数据包以及如何路由数据包&#xff0c;它是随着互联网的出现而…

Pytorch基础:Tensor的reshape方法

相关阅读 Pytorch基础https://blog.csdn.net/weixin_45791458/category_12457644.html?spm1001.2014.3001.5482 在Pytorch中&#xff0c;reshape是Tensor的一个重要方法&#xff0c;它与Numpy中的reshape类似&#xff0c;用于返回一个改变了形状但数据和数据顺序和原来一致的…

linux入门---信号的理解

目录标题 如何理解计算机中的信号如何查看计算机中的信号初步了解信号的保存和发送如何向目标进程发送信号情景一&#xff1a;使用键盘发送信号情景二&#xff1a;系统调用发送信号情景三&#xff1a;硬件异常产生信号情景四&#xff1a;软件条件产生信号 核心转储信号的两个问…

单调栈---基础数据结构与算法

简介 栈 (stack) 又名堆栈&#xff0c;是一种数据结构&#xff0c;向一个栈插入新元素又称作进栈、入栈或压栈&#xff0c;从一个栈删除元素又称作出栈或退栈。 栈是一种只允许在表尾进行插入和删除操作的线性表&#xff0c;也就是我们所说的后进先出&#xff0c;我们把栈想象…

【Linux】ping命令详解

目录 一、ping概述 二、Ping用法 三、ping参数详解 四、使用 五、Wireshark抓取ICMP请求应答消息 一、ping概述 ping 命令用于测试与目标主机之间的连接。它向目标主机发送一个ICMP&#xff08;Internet Control Message Protocol&#xff09;Internet控制报文协议回显请求…

知识图谱小白入门(1):neo4j的安装与CQL的使用

文章目录 序一、安装neo4j1.1 下载neo4j1.2 安装JDK1.3 BUG&#xff1a;dbms failed to start 二、CQL语法2.1 CQL语法创建节点查询节点创建关系查询关系2.2 习题 习题答案 序 知识图谱&#xff0c;是一种实体间的信息与关系知识的网状结构&#xff0c;借用图论中点与边的概念…

SLAM从入门到精通(用python实现机器人运动控制)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在ROS下面&#xff0c;开发的方法很多&#xff0c;可以是c&#xff0c;可以是python。大部分接口操作类的应用&#xff0c;其实都可以用python来开…

「专题速递」数字人直播带货、传统行业数字化升级、远程协作中的低延时视频、地产物业中的通讯终端...

音视频技术作为企业数字化转型的核心要素之一&#xff0c;已在各行各业展现出广泛的应用和卓越的价值。实时通信、社交互动、高清视频等技术不仅令传统行业焕发新生&#xff0c;还为其在生产、管理、服务提供与维护等各个领域带来了巨大的助力&#xff0c;实现了生产效率和服务…

postgresql-聚合函数增强功能

postgresql-聚合函数增强功能 按季度统计入职员工 按季度统计入职员工 select -- extract截取&#xff0c;按季度进行统计入职员工总数 extract(year from hire_date), count(*) filter(where extract(quarter from hire_date) 1) "第一季度", count(*) filter(wh…

httpserver 下载服务器demo 以及libevent版本的 httpserver

实现效果如下&#xff1a; 图片可以直接显示 cpp h 这些可以直接显示 其他的 则是提示是否要下载 单线程 还有bug 代码如下 先放上来 #include "httpserver.h" #include "stdio.h" #include <stdlib.h> #include <arpa/inet.h> #include…

录屏软件——Vizard

Vizard&#xff0c;美且实用的网页端录屏软件&#xff0c;轻巧不占内存。Windows/Mac OS均适用。 可以录电脑操作、录软件教程、录网课、录bug、录工作汇报、录创作素材&#xff08;游戏&#xff09;……几乎能想到的一切录屏场景。 除了完全免费的在线录屏&#xff0c;Vizar…

激光雷达中实现F-P标准具高热稳定性的帕尔贴精密温控解决方案

摘要&#xff1a;法布里-珀罗标准具作为一种具有高温度敏感性的精密干涉分光器件&#xff0c;在具体应用中对热稳定性具有很高的要求&#xff0c;如温度波动不能超过0.01℃&#xff0c;为此本文提出了相应的高精度恒温控制解决方案。解决方案具体针对温度控制精度和温度均匀性控…

c++中的动态内存管理

目录 1.内存分布 2.c语言动态内存管理 3.c动态内存管理 4.operator new 与operator delete 函数 5.定位new 6.malloc/free 与 new/delete 的区别 1.内存分布 首先我们需要了解一下数据在内存中的分布&#xff0c;请看以下代码&#xff1a; int globalVar 1; static in…

C#停车场管理系统

目录 一、绪论1.1内容简介及意义1.2开发工具及技术介绍 二、总体设计2.1系统总体架构2.2登录模块总体设计2.3主界面模块总体设计2.4停车证管理模块总体设计2.5停车位管理模块总体设计2.6员工管理模块总体设计2.7其他模块总体设计 三、详细设计3.1登录模块设计3.2主界面模块设计…

想要精通算法和SQL的成长之路 - 并查集的运用和案例(省份数量)

想要精通算法和SQL的成长之路 - 并查集的运用 前言一. 并查集的使用和模板1.1 初始化1.2 find 查找函数1.3 union 合并集合1.4 connected 判断相连性1.5 完整代码 二. 运用案例 - 省份数量 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 并查集的使用和模板 先说一下并查集…

力扣:119. 杨辉三角 II(Python3)

题目&#xff1a; 给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09…

计算机竞赛 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…

JavaScript:从入门到进阶的旅程

JavaScript是一种广泛使用的编程语言&#xff0c;为网页和应用程序提供了交互性和动态性。从初学者到资深开发者&#xff0c;JavaScript都是一项值得掌握的技能。在本文中&#xff0c;我们将探讨JavaScript的基础知识&#xff0c;以及一些进阶的概念和技巧。 一、JavaScript简…

Spring的注解开发-注解原理解析-xml方式/注解方式组件扫描

目录 Spring注解的解析原理 xml配置组件扫描 注解方式配置组件扫描 原理图 yysy&#xff0c;没有搞太明白&#xff0c;真的复杂&#xff0c;欢迎大佬留言解惑 Spring注解的解析原理 使用Component等注解配置完毕后&#xff0c;要配置组件扫描才能使注解生效 xml配置组件扫…

2023年【高压电工】证考试及高压电工复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 高压电工证考试根据新高压电工考试大纲要求&#xff0c;安全生产模拟考试一点通将高压电工模拟考试试题进行汇编&#xff0c;组成一套高压电工全真模拟考试试题&#xff0c;学员可通过高压电工复审模拟考试全真模拟&a…