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

Java泛型5——泛型通配符

注:以下内容基于Java 8,所有代码都已在Java 8环境下测试通过

目录:

  • Java泛型1——概述
  • Java泛型2——泛型类
  • Java泛型3——泛型接口
  • Java泛型4——泛型方法
  • Java泛型5——泛型通配符
  • Java泛型6——类型擦除

什么是通配符

在Java中,类与类之间是有继承关系的。例如,Integer 类继承自 Number 类,因此Integer 类的对象可以赋值给 Number 类的引用(即向上转型,这是可以实现多态性的一个重要因素)。但集合之间没有这种关系,也就是 LinkedList<Integer>LinkedList<Number>之间并没有继承关系,它们都是LinkedList。因此 LinkedList<Number> 的集合并不能存放Integer 类型的变量(虽然Integer 类继承自 Number 类)。

比如下面这段代码:

public class Main {private static void dealTest(Test<Father> test) {System.out.println(test.getClass());}public static void main(String[] args) {Test<Father> tesF = new Test<>();Test<Child> testC = new Test<>();Main.dealTest(tesF);Main.dealTest(testC);//编译器报错}
}class Father {}class Child extends Father {}class Test<T> {}

这段代码定义了一个泛型类 Test ,并定义了一个处理该类的静态方法 dealTest(),该类接受一个 Test<Father> 对象作为参数。根据上面的介绍可以知道,虽然ChildFather 的子类,但Test<Child>Test<Father> 之间并没有继承关系,因此静态方法 dealTest()不能接受一个 Test<Son> 对象。因此,若想让静态方法 dealTest()处理Test<Son> 对象,还需对其进行重载:

private static void dealTest(Test<Child> test) {}

但这显然违背了多态性的设计理念,而且这是编译器不允许的做法。如果能让 dealTest()方法不只接受Test<Father>对象,而是让其接受Test<XXX>对象,其中XXX代表某一类型内的类型参数,那么上面这个问题就可以解决了。

这就是泛型通配符的作用:泛型通配符用于限制类型参数的范围。

泛型通配符有 3 种形式:

  • <?> :无界通配符
  • <? extends T> :有上界的通配符
  • <? super T> :有下界的通配符

无界通配符

无界通配符:<?>,其中 ? 代表了任意一种数据类型。比如,下面这段代码:

public class Main {private static void dealTest(Test<?> test) {//?代表可以使用任意一种数据类型System.out.println(test.getClass());}public static void main(String[] args) {Test<Father> tesF = new Test<>();Test<Child> testC = new Test<>();Test<Integer> testI = new Test<>();Main.dealTest(tesF);Main.dealTest(testC);Main.dealTest(testI);}
}class Father {}class Child extends Father {}class Test<T> {}

由于使用了无界通配符,dealTest()方法可以接受具有不同泛型参数的泛型类 Test的对象。

需要注意:

  • 不要混淆 Test<Object>Test<?>Object 也是一种数据类型,因此 Test<Object> 代表参数类型只能为ObjectTestTest<?>代表参数类型可以是任意数据类型的Test

  • 最后不要在实例化泛型类的时候使用无界通配符<?> 集合的数据类型是不确定的,因此我们只能往集合中添加null,而且从其中取出的元素也只能赋值给Object对象。

    import java.util.LinkedList;public class Main {public static void main(String[] args) {LinkedList<?> list = new LinkedList<>();list.add(null);list.add(1);//编译器报错,只能放入null}
    }
    

上界通配符

上界通配符:<? extends T>,其中T 代表了类型参数的上界。上界通配符将类型参数限制为特定类型T及其子类型。比如,<? extends Number>表示类型参数可以是Number以及Number的子类。

可以使用上界通配符对上面的代码进行改写:

public class Main {private static void dealTest(Test<? extends Father> test) {//<? extends Father> 代表可以使用 Father 及其子类作为类型参数System.out.println(test.getClass());}public static void main(String[] args) {Test<Father> fatherTest = new Test<>();Test<Child> childTest = new Test<>();Main.dealTest(fatherTest);Main.dealTest(childTest);}
}class Father {}class Child extends Father {}class Test<T> {}

LinkedList<? extends Number> 为例,在使用上界通配符的时候需要注意:

LinkedList<? extends Number> 可以代表 LinkedList<? extends Interger>LinkedList<? extends Double>……但是,不能指定 LinkedList<? extends Number>的数据类型。如下:

import java.util.LinkedList;public class Main {public static void main(String[] args) {LinkedList<? extends Number> list1 = new LinkedList<Integer>();//编译正确LinkedList<? extends Number> list2 = new LinkedList<Double>();//编译正确LinkedList<? extends Number> list3 = new LinkedList<Object>();//编译器报错,超出上界LinkedList<Number> list4 = new LinkedList<Integer>();//编译器报错list1.add(1);//编译器报错list1.add(2.3);//编译器报错list1.add(null);//编译正确}
}

在看上面的代码之前,需要明确一个概念,那就是 LinkedList<? extends Number>表示这个集合可能是 LinkedList<? extends Interger>也可能是 LinkedList<? extends Double>,但它什么都可能是的后果就是它什么也不是,也就是说不能确定它到底是 LinkedList<? extends Interger>还是 LinkedList<? extends Double>或者其他什么集合,所以也就不能往里面添加具体类型的元素,因为不能确定它是什么类型的。但和无界通配符类似,可以往里面添加null

下界通配符

下界通配符:<? super T>,与上界通配符刚好相反,T代表了类型参数的下界。类似地,下界通配符将类型参数限制为特定类型T及其超类。比如,<? extends Integer>表示类型参数可以是Integer以及Integer的超类。

可以使用下界通配符对上面的代码进行改写:

public class Main {private static void dealTest(Test<? super Child> test) {//<? super Child> 代表可以使用 Child 及其超类作为类型参数System.out.println(test.getClass());}public static void main(String[] args) {Test<Father> fatherTest = new Test<>();Test<Child> childTest = new Test<>();Main.dealTest(fatherTest);Main.dealTest(childTest);}
}class Father {}class Child extends Father {}class Test<T> {}

带有上界统配符的集合LinkedList<? extends Number>不能添加具体类型的元素,但是带有下界通配符的集合LinkedList<? super Number>可以添加Number类及其子类的对象,但是不能添加Number类的父类对象。因为LinkedList<? extends Number>最低也是个LinkedList<Number extends Number>集合,因此至少也能存放Number类对象,所以也可以存放Number子类对象。但是LinkedList<? extends Number>的上限不知道,所以类似于带有上界通配符的集合不能存放具体的数据类型,LinkedList<? extends Number>也不能存放Number父类的对象。

import java.util.LinkedList;public class Main {public static void main(String[] args) {LinkedList<? super Number> list1 = new LinkedList<Object>();//编译正确LinkedList<? super Number> list2 = new LinkedList<Integer>();//编译器报错,超出下界list1.add(1);//编译正确list1.add((Object) 2.5);//编译器报错,不能存放 Number 类的父类对象}
}

相关文章:

Java泛型5——泛型通配符

注&#xff1a;以下内容基于Java 8&#xff0c;所有代码都已在Java 8环境下测试通过 目录&#xff1a; Java泛型1——概述Java泛型2——泛型类Java泛型3——泛型接口Java泛型4——泛型方法Java泛型5——泛型通配符Java泛型6——类型擦除 什么是通配符 在Java中&#xff0c;类…...

牛客 AB25 ranko的手表 JAVA 枚举

描述 ranko 的手表坏了&#xff0c;正常应该显示 xx:xx 的形式&#xff08;4 个数字&#xff09;&#xff0c;比如下午 1 点半应该显示 13:30 &#xff0c;但现在经常会有一些数字有概率无法显示。 ranko 在 &#xfffd;1t1​ 时刻看了下时间&#xff0c;过了一段时间在 &am…...

常微分方程建模R包ecode(二)——绘制相速矢量场

本节中我们考虑一个更为复杂的常微分方程模型&#xff0c; d X C d t ν ( X A Y A ) − β ⋅ X C ⋅ ( Y C Y A ) − ( μ g ) ⋅ X C , ( 1 ) d Y C d t β ⋅ X C ⋅ ( Y C Y A ) − ( μ g ρ ) ⋅ Y C , ( 2 ) d X A d t g ⋅ X C − β ⋅ X A ⋅ ( Y C Y A …...

学习C#编写上位机的基础知识和入门步骤:

00001. 掌握C#编程语言基础和.NET框架的使用。 00002. 学习WinForm窗体应用程序开发技术&#xff0c;包括控件的使用和事件驱动编程。 00003. 熟悉基本的数据结构和算法知识&#xff0c;如链表、栈、队列等。 00004. 理解串口通信协议和通信方法&#xff0c;用于与底层硬件设…...

简单高效!低代码搭建销售自动化程序的方法与实践

在当今数字化时代&#xff0c;销售自动化成为了提高销售效率和业绩的重要手段之一。而低代码平台的兴起&#xff0c;使得搭建销售自动化程序变得更加简单和高效。本文将介绍低代码平台及其优势&#xff0c;并探讨如何利用低代码平台搭建销售自动化程序。 1、低代码平台 1&…...

第九十三回 在Flutter中mock数据

文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了"在Flutter中解析JSON数据"相关的内容&#xff0c;本章回中将介绍 如何mock数据.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在本章回中介绍的mock数据主要是通过相关的代码模拟服务器…...

进程与线程的区别与联系

多进程已经可以很好的实现并发编程的效果了&#xff0c;但是仍然有一个明显的缺点&#xff1a;进程太重了&#xff0c;进程消耗的资源更多&#xff0c;速度更慢。如果进程创建销毁不频繁&#xff0c;那么还好&#xff0c;一旦需要大规模创建和销毁进程&#xff0c;开销就比较大…...

使用gadl对土地利用栅格重分类

要使用Python语言进行土地利用栅格的重分类&#xff0c;可以使用gadl库&#xff08;GDAL的Python绑定&#xff09;来实现。gadl库提供了一组功能强大的函数和类&#xff0c;可用于读取、处理和分析栅格数据。 首先&#xff0c;确保已经安装了gadl库。可以使用以下命令通过pip进…...

SQL-每日一题【1141. 查询近30天活跃用户数】

题目 活动记录表&#xff1a;Activity 请写SQL查询出截至 2019-07-27&#xff08;包含2019-07-27&#xff09;&#xff0c;近 30 天的每日活跃用户数&#xff08;当天只要有一条活动记录&#xff0c;即为活跃用户&#xff09;。 以 任意顺序 返回结果表。 查询结果示例如下。…...

Java小型操作系统模拟(采用策略模式结合反射进行搭建,支持一些简单的命令)

Java小型操作系统模拟 项目说明第一阶段&#xff1a;反射结合策略模式搭建基本的命令结构第二阶段&#xff1a;注解结合反射与策略模式&#xff0c;将结构进一步规范第三阶段&#xff1a;开启新的窗口&#xff0c;将控制台输入切换到新窗口中&#xff0c;同时创建右键菜单&…...

VsCode与Idea编辑器更换背景图

目录 VsCode Idea VsCode 需要安装background插件 安装完成后&#xff0c;打开设置&#xff0c;搜索background 然后就可以在json文件进行图片设置&#xff0c;透明度等等 Idea 打开File -> Settings 然后找到Appearance &#xff0c; 往下滑&#xff0c;找到BackGround …...

Visual Studio 快捷键

记录一下VS的快捷键,用Xcode几个星期后回到VS一下子有点乱,还好有条件反射在,过了会就都恢复了 目录 跳转快捷键查找快捷键编辑快捷键代码折叠书签操作记忆来源VS一定要装VAssistX插件,下面的快捷键部分是VX提供的。 跳转快捷键 快速打开文件 Alt + Shift + O 快速打开对…...

IT技术面试中常见的问题及解答技巧

在IT技术面试中&#xff0c;面试官常常会问到一些常见的问题&#xff0c;针对这些问题&#xff0c;我们可以充分准备和提前准备一些解答技巧。下面我将分享一些我个人的经验和观察&#xff0c;希望对大家有所帮助。 请介绍一下你的项目经验。 在回答这个问题时&#xff0c;我们…...

Java使用hive连接kyuubi

一、Maven依赖 <dependency><groupId>org.apache.hive</groupId><artifactId>hive-jdbc</artifactId><version>2.3.9</version> </dependency> 二、相关配置信息 驱动类&#xff1a;org.apache.hive.jdbc.HiveDriver连接UR…...

性能测试基础知识(三)性能指标

性能测试基础知识&#xff08;三&#xff09;性能指标 前言一、时间特性1、响应时间2、并发数3、吞吐量&#xff08;TPS&#xff09; 二、资源特性1、CPU利用率2、内存利用率3、I/O利用率4、网络带宽使用率5、网络传输速率&#xff08;MB/s&#xff09; 三、实例场景 前言 性能…...

【 Redis】的乱码问题

问题描述&#xff1a; 使用RedisTemplate存储的数据&#xff0c;在 redis-cli 客户端查看时&#xff0c;key 和 value 都会携带类似\xac\xad\这样的字符串。 原因&#xff1a; 由于默认使用了 jdk 的序列化方式。以下是支持的序列化方式 项目一般都会有缓存&#xff0c;常常…...

虚拟机安装的问题

CentOS7报错: Host SMBus Controller not enabled! 1.在上图界面中直接输入root用户的密码登录到系统 2.输入命令&#xff0c;lsmod | grep i2c 3.输入命令&#xff0c;vi /etc/modprobe.d/blacklist.conf 创建黑名单&#xff0c;添加以下内容&#xff1a; blacklist i2c_piix…...

seldom之数据驱动

seldom之数据驱动 如果自动化某个功能&#xff0c;测试数据不一样而操作步骤是一样的&#xff0c;那么就可以使用参数化来节省测试代码。 seldom是我在维护一个Web UI自动化测试框&#xff0c;这里跟大家分享seldom参数化的实现。 GitHub&#xff1a;GitHub - SeldomQA/seld…...

设计模式:生成器模式

这个模式书上讲的比较简单&#xff0c;但是感觉精华应该是讲到了。 引用下其它博客的总结&#xff1a;生成器模式的核心在于分离构建算法和具体的构造实现&#xff0c;从而使得构建算法可以重用。 【设计模式】建造者模式_鼠晓的博客-CSDN博客...

Gradle同步任务一直不动问题(非网络情况)

最近更新ComposeViews的Kotlin和Compose版本,升级到Kotlin1.9和Compose1.4.3时遇见一个问题,Gradle同步时始终会卡在一个位置,同步了一晚上也没用 然后又试了两次还是不行,猜测可能是Gradle的问题,于是使用命令行进行同步,并打印debug日志 ./gradlew -debug -refresh-dependen…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...