java基础知识——24.泛型

news2024/11/26 22:53:12

这篇文章我们来讲一下java的泛型

目录

1.什么是泛型

1.1 泛型的概念

1.2 泛型的好处

1.3 粗看泛型集合的源码

2.泛型类

2.1 泛型类的定义

2.2 从泛型类派生子类

3.泛型接口

4.泛型方法

5.类型通配符

5.1类型通配符上限

5.2 类型通配符的下限

6.类型擦除

6.1无限制类型擦除

6.2有限制类型擦除

6.3桥接方法

7.泛型与数组

8.泛型和反射


1.什么是泛型

首先,我们来讲一下java推出泛型的背景

JAVA推出泛型以前,程序员可以构建一个元素类型为Object的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要程序员明确知道存储每个元素的数据类型,否则很容易引发ClassCastException异常。

这样说可能不好理解,下面就用具体的例子来讲一下。

看如下代码:

首先,我们定义一个集合list,因为没有指定类型,所以java就默认为Object类型的,然后我们通过add方法,往里面添加元素,可以看到是可以添加的,因为在添加时进行默认的类型转换。然后我们将其输出打印,通过get方法可以获取到元素,因为里面都是Object类型的数据,所以我们定义一个Object类型的变量来接收。而对于集合中的元素,我们通常都是需要使用的,使用时就要用到明确的类型,所以我们可以将其强转为String类型,可以看到编译时没有报错,然后我们运行看一下结果

报错了,报的是ClassCastException错误,而我们可以明确的看到,在书写代码时,它没有报错,也就是说编译时没有报错,但是在运行时它报错了,这是很可怕的。

 通过这个例子,我们就可以看到,我们需要使用泛型

1.1 泛型的概念

Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构

泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数

下面用具体的例子来说明一下:

此时,我们调用add方法添加时,就指定添加的元素为String类型了

如果我们添加非String类型的数据就会在编译时报错了

下面写完,看一下运行结果:

1.2 泛型的好处

下面说一下泛型的好处:

  • 编译期间自动进行类型检查(类型安全)
  • 减少了数据类型的转换(消除了强制类型转换)

1.3 粗看泛型集合的源码

下面,我们来粗略的看一下泛型集合的源码

这是开头部分,我们可以看到源码中是<E>,这个E可以理解为一个形参,我们传入泛型的类型就会代替这个E,然后在代码中所有的E都会被我们传入的类型所替换。

2.泛型类

下面,我们来讲解一下泛型类

2.1 泛型类的定义

泛型类的定义语法如下:

class 类名称<类型标识,类型标识,…… >{
    private 泛型标识 变量名;
    …………
}

常用的泛型标识:T,E,K,V

注意:泛型标识可以理解为一种形参,或者直接点,就理解为一种类型

泛型类的使用:

使用语法:类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();

java1.7以后,后面<>中的具体的数据类型可以省略不写,那么使用语法就变为了:

类名<具体的数据类型> 对象名 = new 类名<>();

下面,通过具体实例来看一下:

这个就是很简单的一个泛型类的定义

这个是测试代码

没啥好说的,就是很简单指定类型,然后传入类型而已

注意事项:

  • 泛型类,如果没有指定具体的数据类型,此时,操作类型是Object
  • 泛型的类型参数只能是类类型,不能是基本数据类型
  • 泛型类型在逻辑上可以看出是多个不同的类型,但实际上都是相同类型

2.2 从泛型类派生子类

下面,我们来看一下从泛型类派生子类

如果子类也是泛型类,子类和父类的泛型类型要一致:

class ChileGeneric<T> extends Generic<t>

如果子类不是泛型类,父类要明确泛型的数据类型

class ChildGeneric extends Generic<String>

下面来看一下具体实例:

当子类不是泛型类的时候,和上面差不多

注意:在泛型中,你指定类型了,那就以指定的类型为准,没有指定类型,那就默认为Object类型

3.泛型接口

下面来讲一下泛型接口

泛型接口的定义语法:

interface 接口名称 <泛型标识,泛型标识,……>{
    泛型标识 方法名();
    ……
}

泛型接口的使用:

  • 实现类不是泛型类,接口要明确数据类型
  • 实现类也是泛型类,实现类和接口的泛型类型要一致

下面通过具体实例来看一下:

接口的测试和普通接口是一样的,这里就不多说了

4.泛型方法

下面来讲一下泛型方法

泛型方法,是在调用方法的时候指明泛型的类型(泛型类,是在实例化类的时候指明泛型类型)

语法格式:

修饰符<T,E,……>返回值类型 方法名(形参列表){
    方法体……
}

注意:

  • public与返回值中间的<T>非常重要,可以理解为声明此类方法为泛型方法。
  • 只有声明了<T>的方法才是泛型方法,泛型类中的使用了返校的成员方法并不是泛型方法。
  • <T>声明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T
  • 与泛型类的定义一样此处T可以随便写任意标识,常见的如T,E,K,V等形式参数常用于表示泛型

下面通过具体实例来看一下

 这就是一个泛型方法。注意,在泛型方法中,如果方法的形参或者方法里面都需要使用到泛型,那么泛型标识必须一致。

下面不写具体代码,就简单的思考一下。上面的泛型方法是写明了泛型标识符,我们知道,泛型就是用来规定类型的,方法的类型是与它的返回值有关的。如果,我们没有返回值,那么就可以不用写泛型标识了,此时只需要写void就可以了。其实就是很简单的一个内容。有返回值,那么必定要写明类型,于是就用到泛型;没有返回值,就没必要写类型,那就直接用void,就没泛型的事了

5.类型通配符

下面我们来讲一下类型通配符

什么是类型通配符?

类型通配符一般是使用“?”代替具体的类型实参,所以类型通配符是类型实参,而不是类型形参。

下面来看一下具体实例

如图所示,当我们类的泛型改变时,方法就不可以用了(注意:Integer是继承Number的,按照多态的思想,这里是可以通过的,但是在泛型这里,多态是不允许的,因为泛型类的本质是同一个类)

错误的解决方法:

如果再写一个方法,也会报错,因为这不构成方法的重载;如果将方法中的Number改为Object,也不行,因为不支持多态。

正确的解决方法:

使用泛型通配符

即如下图所示:

5.1类型通配符上限

下面,来讲一下通配符的上限

语法格式:

类/接口 <? extends 实参类型>

 要求该泛型的类型,只能是实参类型,或实参类型的子类型

下面通过具体例子来看一下:

如第13行所示,我们将里面的泛型改为<? extends Number>,意思是我们只能传Number或者Number的子类的类型,所以在第14行,我们就可以直接用Number类型的变量去接收(多态),这时,我们可以看到,当我们传入Integer时,没有报错,所以没有问题。

这就是所谓的类型通配符上限,它规定了泛型所能传入的类型的上限(或者说父类)是什么。

5.2 类型通配符的下限

下面,来讲一下通配符的上限

语法格式:

类/接口 <? super 实参类型>

要求该泛型的类型,只能是实参类型,或实参类型的父类型

下面通过具体例子来看一下:

如第13行所示,我们将里面的泛型改为<? super Integer>,意思是我们只能传Integer或者Integer的父类的类型,所以在第14行,我们就可以用Object类型的变量去接收(多态),这时,我们可以看到,当我们传入Number时,没有报错,所以没有问题。

这就是所谓的类型通配符下限,它规定了泛型所能传入的类型的下限(或者说子类)是什么。

6.类型擦除

下面,我们来讲一下java的类型擦除

概念:

泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很好地和之前版本的代码兼容。那是因为,泛型信息只存在于代码编译阶段,在进入JVM之前,与泛型相关的信息会被擦除掉,我们称之为——类型擦除。、

下面我们来看一下例子:

结果为true,说明list1和list2是同一个类,也就是它两是同一类型,也就是说他们的类型(Integer和String)被擦除了

6.1无限制类型擦除

下面来看一下类型擦除的无限制类型擦除

意思就是我们在编写泛型类的时候,编写完后JVM在编译的时候,里面的泛型标识直接用Object来代替

6.2有限制类型擦除

下面来看一下类型擦除的有限制类型擦除

意思就是我们在编写泛型类的时候,如果用到泛型上限,那么编写完后JVM在编译的时候,里面的泛型标识直接用上限来代替

6.3桥接方法

桥接方法在接口中有用到,它是为了保持类和接口的实现关系

 

7.泛型与数组

下面我们来讲一下泛型数组

 泛型数组的创建

  • 可以声明待泛型的数组引用,但是不能直接创建带泛型的数组对象
  • 可以通过 java.lang.reflect.Array的newInstance(Class<T>,int)创建T[ ]数组

下面,通过具体例子来看一下:

这个是错误演示:

 正确方法:

这就是正确写法,如果再出现上面的错误,它就好显示错误了

另一种方法:

这就是第二种创建泛型数组的方法,可能比较难,但是仔细看是可以理解的

8.泛型和反射

最后我们来说一下泛型和反射

反射常用的泛型类:Class<T>;Constructor<T>

下面用具体实例来看一下:

没什么问题

至此,我们的泛型粗略的讲完了,在java中泛型是一个比较重要的章节,大家要掌握。

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

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

相关文章

HTML(三) -- 表单设计

目录 1. 基本语法 2. 表单控件 2.1 input控件 input 常用属性&#xff1a; input type的表单项&#xff1a; 2.2 select 控件 2.3 textarea控件 2.4 label 控件 为什么需要表单&#xff1f; 在我们网页中&#xff0c; 无论是提交搜索的信息&#xff0c;还是网上注…

线程池核心线程是如何保持住的?

概述 本文尝试回答以下几个问题&#xff1a; 1、核心线程池是如何保持住的&#xff1f; 2、当没有任务时&#xff0c;超过核心线程数的线程是如何回收的&#xff1f; 3、线程队列为什么必须是BlockingQueue&#xff0c;普通队列行不行&#xff1f; 背景知识 以下是一些背景知…

第十三章 移动和旋转(上)

移动和旋转是游戏对象最频繁地操作。我们上个章节简单介绍了Cube的移动和旋转。移动是修改transform的position属性&#xff0c;旋转是修改transform的eulerAngles&#xff08;欧拉角&#xff09;属性&#xff0c;两者属性值均可以使用Vector3向量来实现。需要大家注意的是&…

C#窗体将DGV控件中数据导入导出Excel表

目录 界面图&#xff1a; 效果视频&#xff1a; 一&#xff1a;将DGV数据导出到Excel表中 二&#xff1a;将Excel表数据导入到DGV中 三&#xff1a;界面全部代码 界面图&#xff1a; 效果视频&#xff1a; DGV数据导入导出Excel 一&#xff1a;将DGV数据导出到Excel表中 p…

私人影院 - 本地搭建Emby媒体库服务器并在外远程访问 「无需公网IP」

文章目录 1.前言2. Emby网站搭建2.1. Emby下载和安装2.2 Emby网页测试 3. 本地网页发布3.1 注册并安装cpolar内网穿透3.2 Cpolar云端设置3.3 Cpolar内网穿透本地设置 4.公网访问测试5.结语 1.前言 在现代五花八门的网络应用场景中&#xff0c;观看视频绝对是主力应用场景之一&…

用ChatGPT问DotNet的相关问题,发现DotNet工程师的前景还不错

本人最近费了九牛二虎之力注册了一个ChatGPT账号&#xff0c;现在就给大家分享一下&#xff0c;问一下关于.NET的问题&#xff0c;看看ChatGPT的AI功能具体如何&#xff1f; 一、C#跟其它语言比较的优势 回答&#xff1a; C#是一门编程语言&#xff0c;它是为 Microsoft 的 …

【Linux】动态库与静态库

目录 一、前言 二、静态库与动态库 三、生成静态库 1、生成原理 2、完整过程 3、总结 四、生成动态库 1、环境变量 2、建立软链接 3、配置文件 五、动态库的加载 1、动态库加载的过程 2、动态库地址的理解 3、补充内容 一、前言 关于动态库与静态库的一小部分前置…

TCP的粘包和拆包

UDP有数据边界&#xff0c;TCP是没有数据边界&#xff0c;是流协议。如何拆包&#xff0c;就要靠应用层来处理。 四层网络模型&#xff0c;消息在进入每一层时都会多加一个报头。mac头部记录的是硬件的唯一地址&#xff0c;IP头记录的是从哪来和到哪去&#xff0c;传输层头记录…

GPT 护理机器人 - 让护士的工作变简单

引子    书接上文《GPT接入企微应用 - 让工作快乐起来》&#xff0c;我把GPT接入了企微应用&#xff0c;不少同事都开始尝试起来了。有的浅尝辄止&#xff0c;有的刨根问底&#xff0c;五花八门&#xff0c;无所不有。这里摘抄几份&#xff1a; “帮我写一份表白信&#xff…

Github 的使用

3. Github 在版本控制系统中&#xff0c;大约90%的操作都是在本地仓库中进行的&#xff1a;暂存&#xff0c;提交&#xff0c;查看状态或者历史记录等等。除此之外&#xff0c;如果仅仅只有你一个人在这个项目里工作&#xff0c;你永远没有机会需要设置一个远程仓库。只有当你…

嗯,这个树怎么和往常不一样?

文章目录 前言一、二叉树的链式存储二、二叉树链式结构的实现二叉树的结构设计手动构建二叉树二叉树的前序遍历二叉树的中序遍历二叉树的后序遍历二叉树的层序遍历计算二叉树大小计算叶子节点个数计算二叉树高度计算第K层的节点个数查找某个值对应的节点二叉树的销毁 三、完整代…

全球首个存量手机直连卫星天地语音通话,打通了!

4月25日&#xff0c;美国卫星通信初创公司——AST SpaceMobile&#xff0c;宣布打通了全球首个天基蜂窝语音通话。 对于卫星通信乃至整个通信行业来说&#xff0c;这是一个重大新闻&#xff0c;非常值得关注。 去年&#xff0c;我们还只是实现了手机和卫星之间的双向短消息通信…

Page管理机制

Page页分类 Buffer Pool 的底层采用链表数据结构管理Page。在InnoDB访问表记录和索引时会在Page页中缓存&#xff0c;以后使用可以减少磁盘IO操作&#xff0c;提升效率 Page根据状态可以分为三种类型&#xff1a; - free page &#xff1a; 空闲page&#xff0c;未被使用 - …

1.3 HBase 基本架构

架构角色&#xff1a; 1&#xff09;Master 实现类为 HMaster&#xff0c;负责监控集群中所有的 RegionServer 实例。主要作用如下&#xff1a; &#xff08;1&#xff09;管理元数据表格 hbase:meta&#xff0c;接收用户对表格创建修改删除的命令并执行 &#xff08;2&#x…

【C++ Primer(第5版) 课后习题题目及答案 第一章】

C Primer5th 课后习题答案 第一章 1.1&#xff1a;查阅你使用的编译器的文档&#xff0c;确定它所使用的文件命名约定。编译并运行main程序。1.2&#xff1a;改写程序&#xff0c;让它返回-1。返回值-1通常被当作程序错误的标识。重新编译并运行你的程序&#xff0c;观察你的系…

C#弹出消息对话框,增加输入框,接受输入信息

效果图&#xff1a; 代码&#xff1a; using Microsoft.VisualBasic;string intext Interaction.InputBox("请输入密码","输入密码","",Screen.PrimaryScreen.Bounds.Width/4,Screen.PrimaryScreen.Bounds.Height/4);MessageBox.Show("in…

多商户商城系统开发功能有哪些?

多商户商城系统开发功能有哪些&#xff1f; 1、商品管理。商品管理是多商户商城系统的必备功能。商家需要能够轻松地添加、修改和删除商品。这个功能还应该包括商品图片、价格、描述和库存等信息的管理。消费者也需要能够通过小程序浏览商品并下订单。 2、订单管…

图形编辑器:历史记录设计

大家好&#xff0c;我是前端西瓜哥。今天讲一下图形编辑器如何实现历史记录&#xff0c;做到撤销重做。 其实就是版本号的更替。每个版本保存一个状态。 数据结构 要记录图形编辑器的历史记录&#xff0c;支持撤销重做功能&#xff0c;需要两个栈&#xff1a;撤销&#xff0…

【计算机网络】学习笔记:第三章 数据链路层【王道考研】持续更新中....

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

《编码——隐匿在计算机软硬件背后的语言》精炼——第14章(边沿触发器,计数器)

学习不是一次性的投资&#xff0c;而是一份长期稳定的收益。 文章目录 8位锁存器边沿触发器计数器改进的边沿触发器 8位锁存器 上篇文章讲到了1位存储器的组成&#xff0c;将8个1位存储器的时钟端连在一起就形成了一个8位锁存器&#xff0c;如下所示&#xff1a; 这个锁存器一…