泛型知识点总结

2023-11-03

目录

泛型的概念:

泛型的底层实现

什么是类型擦除:

Java编译器具体是如何擦除泛型的

对于泛型的理解:

泛型的使用注意点(零散知识点1):

泛型的使用注意点(零散知识点2):

泛型方法:

类型变量的限定:


泛型的概念:

泛型的底层实现

        我们知道,Java有Java编译器和Java虚拟机,编译器会将Java源代码转换成 .class文件,然后虚拟机加载并运行 .class文件。然而对于泛型类,Java编译器会将泛型代码转换为普通的非泛型代码,(就像没有指定泛型时的普通代码)将泛型类型参数擦除,如何擦除的呢,即将泛型参数替换为object,然后插入必要的强制类型转换。Java虚拟机实际执行的时候,他是不知道泛型这回事的,只知道普通的类及代码。

        泛型这个设计是在jdk5.0之后才出现的,这个设计是为了兼容性而不得已的一个选择,而使用泛型会有更好的安全性、更好的可读性。通过使用泛型,开发环境和编译器能确保不会用错类型,为程序多设置一道安全网,还省去了类型的强制转换。使得运行时可能出现的异常提前到编译时。

        Java的泛型是通过擦除实现的,类定义中的类型参数如果没有指定特定类型,就会被替换为object,如果指定了参数类型,就会被替换为指定类型。在程序运行的过程中,虚拟机是不知道泛型的实际类型参数,比如pair <Integer>,运行只知道pair,而不知道Integer,所以Java的泛型又称为伪泛型。

什么是类型擦除:

(对于虚拟机而言,并没有泛型这一说法,编译器会使用类型擦除来处理泛型类变成普通类。)

无论何时定义一个泛型类型,都会自动提供一个相应的原始类型,这个原始类型的名字就是去掉类型参数后的泛型类型名,类型变量会被擦除并替换为其限定类型,(或者对于无限的变量则替换为object)。例如:在程序中有不同类型的Pair。例如Pair<String>、Pair<LocalDate>。这些在擦除类型后都会变成原始的Pair类型,然而原始类型会用第一个限定来替换类型变量 如上文示例中会替换为Comparable而不是Serializable,或者,如果没有给限定,就替换为object类型,即Pair<object>。然后在必要的时候会使用强制类型转换,使虚拟机识别的来。

Java编译器具体是如何擦除泛型的

  1. 检查泛型类型,获取目标类型
  2. 擦除类型变量,并替换为限定类型
    如果泛型类型的类型变量没有限定(<T>),则用Object作为原始类型
    如果有限定(<T extends XClass>),则用XClass作为原始类型
    如果有多个限定(T extends XClass1&XClass2),则使用第一个边界XClass1作为原始类
  3. 在必要时插入类型转换以保持类型安全

对于泛型的理解:

        泛型可以理解为一种规范、一个标签(即把元素的类型设计成一个参数,这个类型参数叫做泛型),比如:中药店装药的盒子上会有一个空标签,不同的药对应不同的标签,标签为枸杞的盒子只装枸杞,标签为板蓝根的盒子只装板蓝根,装药的盒子上的名字就是一种规范,其中空标签就是泛型参数E,不同的标签名就是对应的指定类型。

       泛型是计算机程序的一种重要的思维方式,它将数据结构与算法和数据类型相分离,使得同一套数据结构和算法可以应用于不同类型的数据类型,而且可以保证类型安全,提高可读性。

       在java中泛型是通过擦除实现的他是java编译器的概念,java虚拟机运行时对泛型基本一无所知。什么是擦除方式呢?后文会提及;

泛型的使用注意点(零散知识点1):

1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内,用逗号隔开。比如:<E1,E2,E3>

2. 在使用泛型之后引入了泛型参数,很多人就以为泛型类很特别,经常会认为泛型类的构造器是这样的   public GenericClass<E>();实际上泛型类的构造参数是这样的 public GenericClass()。他们忽略了在虚拟机的眼里泛型类和基本类毫无区别,编译时编译器会将泛型类以擦除的方式变成非泛型类,所以又称Java的泛型是伪泛型,意思也就是说java虚拟机不认识泛型;

泛型类错误的构造方法:     public GenericClass<E>();

3.实例化后,操作原来泛型位置的结构必须与指定的泛型类型一致。

       这句话的意思很难理解举个例子就很清晰了,对于ArrayList<string>集合中只能存储尖括号中指定的泛型类型的数据,即ArrayList<string>中不能存储double类或者其他非String类型的数据;

4.泛型要使用一路都用。要不用,一路都不要用。

5.泛型如果不指定,将被擦除(就是采用默认为object的方式),泛型对应的类型均按照Object处理,但不等价于Object。

         意思也就是说上面两种方式是不等价的;

6.如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。

7.jdk1.7,泛型的简化操作:ArrayList<Fruit> flist = new ArrayList<>();

即在前面尖括号中指定了泛型类型后,后面的尖括号中可以不指定泛型类型

8.泛型的指定中不能使用基本数据类型,可以使用包装类替换。

        为什么会这样呢?当我们在使用泛型的时候如果不指定它的具体类型那么他默认是object类型,然而object类型是所有引用类型的根,所以我们在指定泛型的时候只能使用引用类型包装类也是属于引用类型体系的;

9.在类/接口上声明的泛型,在本类或本接口中即代表某种类型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型。但在静态方法中不能使用类的泛型。

10.异常类不能是泛型的

11.不能使用new E[ ]。但是可以: E[ ] elements = (E[ ])new Object[capacity](因为E只是一个参数,不是类,你不能直接上来new一个未知参数的数组);参考:ArrayList源码中声明:Object[ ]   elementData,而非泛型参数类型数组。。

12,

结论:子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型

泛型的使用注意点(零散知识点2):

  • 集合接口或集合类在就jdk5.0后修改为带泛型。
  • 实例化集合类时,可以指明具体类型。
  • 指定完数据类型后,在集合类或接口中凡是定义类或接口时,内部结构(方法、构造器、属性)使用到泛型的结构时,都指定为实例化时的泛型类型。
  • 如果实例化时没有用到泛型,系统会(通过擦除的方式实现)默认泛型是java.lang.object类型。
  • 如果用一个明确的类型而不是var声明的一个变量,则可以通过使用菱形语法省略构造器中的类型参数。
  • 在定义了泛型后,我么可以用具体的数据类型替换类型变量来实例化泛型类型,不同的类型变量放到泛型方法中形成不同的普通类。

泛型方法:

泛型方法可以在普通类中定义,也可以在泛型类中定义。注意,类型变量放在修

(这里的修饰符就是public static)的后面,并且在返回类型的前面。

这里值得注意的是,有些情况下我们方法的返回值也可能是泛型参数,那么此时就要格外注意了:以下这个是错误写法:

正确写法如下:

 为什么要在E前面加一个<E>呢?因为,我们的编译器是不知道泛型的,他首先会将E默认为一个class类处理,所以会报错,加上一个<E>是为了标识E是泛型参数而非class类;

类型变量的限定:

例:public static <T extends Comparable & Serializable> T min(T [ ] a)……

 类型变量的限定是指,使类型变量T去继承或实现其他接口或类,这里只会使用extends关键字,原因:他更接近子类型的概念,这是因为java的设计者不打算在另外添加一个新的关键字。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

泛型知识点总结 的相关文章

  • Java中RandomAccessFile的并发

    我正在创建一个RandomAccessFile对象通过多个线程写入文件 在 SSD 上 每个线程都尝试在文件中的特定位置写入直接字节缓冲区 并且我确保线程写入的位置不会与另一个线程重叠 file getChannel write buffe
  • Java中的文字赋值[重复]

    这个问题在这里已经有答案了 定义上有什么区别 double example 23 1d or double example 23 1 为什么long float double可以以l f d结尾 之间没有区别double example 2
  • 帮助我避免 JPA、Hibernate 和 MySQL 的连接超时

    我正在使用 JPA Hibernate 作为提供者 Glassfish 和 MySQL 开发中一切都运行良好 但是当我将应用程序部署到测试服务器并让它运行 大部分空闲 过夜时 我通常会在早上遇到这样的情况 2011 03 09T15 06
  • ResultSet:通过索引检索列值与通过标签检索

    使用 JDBC 时 我经常遇到这样的结构 ResultSet rs ps executeQuery while rs next int id rs getInt 1 Some other actions 我问自己 以及代码作者 为什么不使用
  • Java Spark DataFrameReader java.lang.NegativeArraySizeException

    学习 Spark for java 并尝试阅读 csv文件为DataFrame使用DataFrameReader 甚至不能得到一个超级简单的 csv文件工作 因为我不断收到异常java lang NegativeArraySizeExcep
  • MediaPlayer.create() 始终返回 null

    我以前用过媒体播放器 从来没有遇到过这个问题 每当我尝试使用 MediaPlayer create 时 该方法都会给我 null 并且我无法播放声音 我有什么遗漏的吗 public class Game extends Activity p
  • 按文件名过滤 eclipse 中的警告

    我们使用 Eclipse 进行 Java 开发 并使用 Maven 将 JSP 编译成 servlet 以便在嵌入式 Jetty 实例中使用 这意味着要从 Eclipse 运行该项目 我必须包含 target jsp source 作为源文
  • 强制 Java 最低版本以“java -version:”运行在 Windows 上不起作用

    我想强制应用程序运行的 JVM 最低版本为 1 6 或更高版本 即 1 6 我的理解是 您可以使用 version 命令行参数来执行此操作 我尝试了一下 在Linux下似乎可以正常工作 但在Windows下却不行 LINUX 我在 Linu
  • 如何导入 Java 密钥库中现有的 X.509 证书和私钥以在 SSL 中使用?

    我在 ActiveMQ 配置中有这个
  • Java 中的 MP4 容器编写器

    我想找到一个免费的 Java MP4 容器 编写器 我不需要编码器 只需要能够根据预期值写入正确原子的编码器 Bonus对于这样一个库 也可以编写 有效 F4V 我更喜欢纯 Java 解决方案 而不是使用 JNI 或外部可执行文件的解决方案
  • 为什么我要使用责任链而不是 switch 语句

    考虑一下您已经获得了多次验证 仅当要检查的对象属于某种类型时 这些验证才应生效 为什么我要使用责任链而不是 switch 语句 责任链示例 public class Executor Inject private ValidatorFact
  • 如何使用 Selenium 中的索引切换到窗口

    由于selenium不提供切换到窗口 多个窗口 的方法 但我想使用index html自定义方法来切换到不同的窗口 但下面的代码没有按预期工作 请建议以下方法的最佳实施 public void switchToWindowIndex int
  • vm 参数中的 -D 是什么,它表示为什么我们必须在 vm 参数中始终指定 -D

    vm 参数中的 D 是什么 它表示为什么我们必须在 vm 参数中始终指定 D 有什么标准吗 如果是 那是什么以及指定的位置 D 设置当前运行的 java 程序可以访问的属性值 它允许程序员设置程序运行所需的值 但程序不知道这些值是什么 因此
  • 无法自动装配 org.springframework.mail.javamail.JavaMailSender

    尝试运行我的应用程序时遇到以下问题 所有的东西都调试过了 还是一无所获 IDE 毫无问题地找到了 bean 所以我对这里发生的情况感到非常困惑 SEVERE Exception sending context initialized eve
  • java中日期转换dd-MMM-yyyy到dd-MM-yyyy

    在Java中将23 Mar 2011转换为23 03 2011的最简单方法是什么 感谢大家 这似乎解决了这个问题 try Calendar cal Calendar getInstance cal setTime new SimpleDat
  • Java 不可变对象 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在学习不变性的概念 据我了解 一旦创建对象 不可变对象就无法更改其值 但我不明白不可变对象的以下用途 They are 自动是线程
  • “___ 中的方法 ___() 是在无法访问的类或接口中定义的”编译错误

    我发现了一个奇怪的编译限制 我无法解释 并且我不明白这个限制的原因 示例1 考虑这些类 In package e1 public class C1 enum E1 A B C public E1 x In package e2 import
  • Java LRU 缓存使用 LinkedList

    堆栈溢出的新手 所以请不要介意我以菜鸟的方式问这个问题 我正在尝试使用链表实现 LRU 缓存 我在这里看到了使用 linkedHashMap 和其他数据结构的其他实现 但对于这种情况 我正在尝试使用链表创建最佳优化版本 正如我在技术期间被问
  • Java 中更高级的泛型

    假设我有以下课程 public class FixExpr Expr
  • 更新分页。是否可以?

    他们是否存在一些方法来处理更新分页 例如我有 100 行类型 Id private Integer id Column private boolean flag Column private Date last 一开始它们看起来像 id f

随机推荐

  • git clone no matching host key type found. Their offer: ssh-rsa,ssh-dss... 报错

    Unable to negotiate with 主机地址 port 端口号 no matching host key type found Their offer ssh rsa ssh dss fatal Could not read
  • 红黑树与平衡二叉树区别?

    如果说平衡二叉树是一个类的话 那么红黑树就是该类的一个实例 算法的书我丢久了 一下子也找不到 我是凭记忆说的 红黑树的算法比较麻烦 但它的思想很好 如果理解了它的思想也就理解它的算法 我也只记得思想 具体算法记不得了 我就在这说说思想吧 红
  • oracle归档空间满且启动报错总结

    oracle归档空间满且启动报错总结 今天oracle数据库归档日志过满导致oracle数据库挂掉 解决思路 删除归档日志 看oracle能否可用 如果不可用重启oracle数据库 并把归档关掉 测试库 生产库一定要起归档 在重启数据库的过
  • WIN32 消息总结

    1 键盘消息 键盘会产生如下两种消息 1 按键消息 消息分类 WM KEYDOWN WM KEYUP WM SYSKEYDOWN 系统按键按下时产生 如ALT F10 WM SYSKEYUP 参数 WPARAM 按键的vritual key
  • 【JMeter-Hive】使用JMeter对Hive的查询性能进行压测

    JMeter Hive 使用JMeter对Hive的查询性能进行压测 1 生成测试数据 2 查询性能压测 2 1 创建线程用户并指定参数配置 2 2 创建JDBC Connection Configuration并配置连接信息 2 3 导入
  • C语言题目代码总结解析

    目录 简单版三子棋实现 简单的扫雷的实现 简单的通讯录实现 最大公约数 辗转相除法 判断一个数是否是素数 二分查找 有序数组查找 递归实现字符串反转 递归实现汉诺塔问题 青蛙跳台阶问题 几个字符串库函数的实现 qsort的冒泡实现版本 杨式
  • 用代码写出浪漫__合集(python、matplotlib、Matlab、java绘制爱心、玫瑰花、前端特效玫瑰、爱心)

    活动地址 CSDN21天学习挑战赛 用代码写出浪漫合集 爱心 玫瑰花 本文目录 一 前言 二 用python matplotlib Matlab java绘制爱心 1 爱心图形1 弧线型 显示的文字写在代码里 2 爱心图形2 直线型 显示的
  • openeuler 欧拉操作系统的几个图形界面安装方法

    欧拉操作系统openeuler 安装的时候默认是不带图形界面的 安装完成后如果要使用图形需要手工往系统里面补 目前为止最新的21 09版本ISO安装完后在线源配置里面EPOL源路径是错误的 需要手工修改一下路径 否则是无法更新源里面的软件包
  • let和const 和var 的区别

    1 let和const是什么 声明变量或声明常量l var声明变量 let 代替var 声明变量 const声明常量constant 2 let和const的用法 var一样 var username Alex let age 18 con
  • 图解LeetCode14:最长公共前缀(递归,二分查找)

    LeetCode14 最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀 如果不存在公共前缀 返回空字符串 示例 输入 strs flowers flow flight 输出 fl 输入 strs dog racecar car 输
  • Linux的shell入门和版本控制(五)

    0 前言 这部分简单介绍了Linux系统中的shell编程 1 服务监听 在Linux中的服务监听 相当于在windows中的任务管理器 常用指令 示例一 查询进程 ps aux grep 要查询的程序名 这样查询会连带这条查询指令的进程一
  • 嵌入式Linux开发: 从0开始编译并启动ARM Linux内核(全志)

    引言 最近看见很多小白不会编译Linux内核 自己瞎折腾走了很多弯路 本文章将会以Orange Pi 香橙派 Zero开发板为例 带您成功编译内核并在板子上启动它 准备 您需要一台Ubuntu PC 版本最好在20 04以上 一个可以用的U
  • TCGA数据库详解

    TCGA The cancer genome atlas 癌症基因组图谱 由 National Cancer Institute NCI 美国国家癌症研究所 和 National Human Genome Research Institut
  • C#位运算示例

    在C 中可以对整型运算对象按位进行逻辑运算 按位进行逻辑运算的意义是 依次取被运算对象的每个位 进行逻辑运算 每个位的逻辑运算结果是结果值的每个位 C 支持的位逻辑运算符如表2 9所示 运算符号 意义 运算对象类型 运算结果类型 对象数 实
  • 即将成为史上最具用户体验的Hexo+GitHub Pages搭建博客的教程(持续更新中)

    前言 网上关于Hexo Github Pages搭建博客的教程很多 但是参阅很多博文 都是表达不够清晰 绕来绕去 基于此 我想以一个初来者的角度写一篇尽可能靠谱的教程 方便大家快速搭建好 大致流程 搭建Node js环境 搭建Git环境 搭
  • c++ 习题(1)

    1 输入一个正整数n 计算下式的和求e的值 保留4位小数 e 1 输入输出示例 Input n 10 e 2 7183 if 1 include stdio h double facabular int n int sum 1 i for
  • 如何在C语言循环里实现多线程,如何用C语言实现多线程

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 Windows操作系统 C语言实现多线程 include include DWORD APIENTRY ThreadOne LPVOID threadArg printf 线程开始啦 参数是 s
  • 买车注意事项

    YETI 2016创行 车 保险 税 上牌 17 2w 其中裸车15 76w GS4 手动豪华 我的手动豪华117500包上牌 交强险 购置税 全车膜 脚垫 侧蹋 行车记录仪 发动机护板 挡泥板 座套 方向盘套 前两次首保免费 10万公里机
  • Git背后的设计理念

    首先要清楚Git版本管理中提交的概念 通过按行对比 line diff 将有差异的部分作为增量补丁 使用git add添加到暂存区里的每一个文件都会由按行对比得到他们的增量补丁 而使用git commit将暂存区里的所有文件的增量补丁合并起
  • 泛型知识点总结

    目录 泛型的概念 泛型的底层实现 什么是类型擦除 Java编译器具体是如何擦除泛型的 对于泛型的理解 泛型的使用注意点 零散知识点1 泛型的使用注意点 零散知识点2 泛型方法 类型变量的限定 泛型的概念 泛型的底层实现 我们知道 Java有