【再探】Java—泛型

 Java 泛型本质是参数化类型,可以用在类、接口和方法的创建中。

1 “擦除式”泛型

Java的“擦除式”的泛型实现一直受到开发者的诟病。

“擦除式”的实现几乎只需要在Javac编译器上做出改进即可,不要改动字节码、虚拟机,也保证了以前没有使用泛型的库可以之间运行在java 5.0 之上。但是这个带来了以下弊端:

  1. 例如对于List<String> 和 List<Integer> ,在运行时由于擦除了,所以这两个都变成了List,因此它们在运行中是同一类型。(而对于C#的泛型来说,无论在源码中、编译后及运行时它们始终是不同的类型)。这导致在运行时,获取不到类型信息。
  2. “擦除式”的实现,是在元素被赋值时编译器自动插入类型检查指令,访问元素时,自动插入类型强制转换指令。这样频繁的类型检查及转换,导致Java的泛型性能差于C#的泛型。
public class EraseGeneric {private static class Holder<T> {T t;public T getT() {return t;}public void setT(T t) {this.t = t;}}public static void main(String[] args) {Holder<String> holder = new Holder<>();holder.setT("hello");String str = holder.getT();}}

图 Holder类被编译后的字节码片段

图 main 方法中,对于Holder类型的赋值及访问操作字节码

1.1 擦除的补偿

如果要在运行时获取类型信息,那么可以通过引入类型标签来对擦除进行补偿。

public class TypeTagGeneric {private static class User {public User() {}}private static <T> void fun(Class<T> kind) throws InstantiationException, IllegalAccessException {T t = kind.newInstance();System.out.println(t);}public static void main(String[] args) throws InstantiationException, IllegalAccessException {fun(User.class);int[] array1 = new int[10];String[] array2 = new String[10];}}

2 协变与逆变

A 类型是B的父类型,对于某个构造器,构造出的复杂类型A`与B`。

协变

A`仍然是B`的父类型。比如Java中的数组,A[] 仍是B[]的父类型。

逆变

B`是A`的父类型。

抗变

A`与B`没有任何继承关系。例如List<A> 与List<B>没有任何继承关系。

表 协变、逆变与抗变

2.1 数组与泛型

T[] t = new T[10]; 这个代码是错误的,Java中规定不能创建泛型数组。

因为Java 在运行时,无法获取泛型的类型信息,因为在创建数组时,也就无法获取到泛型参数所表示的确切类型。

2.1.1 数组的类型

Java中数组的种类有两种:

  1. 基础类型的数组:[ + 开头大写字母。

int[] : [I

  1. 引用类型的数组:[ + L + 类型。

String[] array2 : [Ljava/lang/String

public class ArrayGeneric {private static class Fruit {}private static class Apple extends Fruit {}public static void main(String[] args) {Fruit[] fruits = new Fruit[10];Apple[] apples = new Apple[10];System.out.println(fruits instanceof Fruit[]); // trueSystem.out.println(fruits instanceof Apple[]); // falseSystem.out.println(apples instanceof Fruit[]); // trueSystem.out.println(apples instanceof Apple[]); // truefruits = apples;
//        apples = fruits; // 编译错误System.out.println(fruits.getClass().getSuperclass()); // class java.lang.ObjectSystem.out.println(apples.getClass().getSuperclass()); // class java.lang.Object
//        getSuperclass() 方法:如果此 Class 表示 Object 类、一个接口、一个基本类型或 void,则返回 null。
//        如果此对象表示一个数组类,则返回表示该 Object 类的 Class 对象。否则返回该类的超类。}}

2.2 通配符

泛型中的通配符用于在两个类型之间建立某种类型的向上转型关系。

协变

? extends T, 例如List<? extends Fruit> list。确定了元素类型的父类为Fruit,但不能确定其确切类型,因此不能往该容器添加新的元素(只能添加null)。但是可以从容器中提取元素,类型为Fruit。

逆变

? super T,例如List<? super Apple> list,确定了元素为Apple的父类,因为可以往容器中添加元素,但不能提取元素。

表 通配符的协变与逆变

public class CovarianceAndContravariance {private static class Fruit {}private static class Apple extends Fruit {}private static <T extends Apple> void setItem(List<? super Apple> list, T item) {list.add(item);}private static Fruit getItem(List<? extends Fruit> list,int pos) {return list.get(pos);}public static void main(String[] args) {List<? super Apple> list = new ArrayList<>();setItem(list,new Apple());List<? extends Fruit> list2 = Arrays.asList(new Fruit(),new Apple());Fruit item = getItem(list2, 0);}}

2.2.1 无界通配符

无界通配符,例如List<?>, 其相当于List<? extends Object>,但不等价于List(相当于List<Object>)。其有两个作用:

  1. 告诉编译器,我用了泛型,只是还没确定哪个类型;
  2. 用于捕获类型。
public class CaptureGeneric {private static class Holder<T> {}private static <T> void fun1(Holder<T> holder) {System.out.println(holder);}private static void fun2(Holder<?> holder) {fun1(holder);}public static void main(String[] args) {Holder holder = new Holder(); //  原生类型fun1(holder); // 警告,Unchecked assignment:fun2(holder); // 不会警告,无边界通配符将不会这个原生类型的类型参数(Object)}}

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

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

相关文章

光伏电站在线监测智能诊断系统:开启无人值守新纪元

光伏电站在线监测智能诊断系统&#xff1a;开启无人值守新纪元 大家都知道光伏电站是通过汲取着太阳的光芒&#xff0c;为人类提供源源不断的电能源。然而&#xff0c;随着光伏电站规模的扩大和复杂性的增加&#xff0c;如何有效提高发电效率、减少人工维护成本&#xff0c;实…

YOLOV5算法多目标检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 随着计算机视觉技术的飞速发展&#xff0c;目标检测已成为许多实际应用场景中的关键技术&…

数据结构之二叉树的超详细讲解(2)--(堆的概念和结构的实现,堆排序和堆排序的应用)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 数据结构之二叉树的超详细讲解(2)--(堆的概念和结构的实现,堆排序和堆排序的应用) 收录于专栏【数据结构初阶】 本专栏旨在分享学习数据结构学习的一点学习笔记…

电脑卸载linux安装windows后每次开机都出现grub

原因分析 这是因为电脑硬盘中还存在linux系统的引导程序&#xff0c;并且启动顺序还在windows之前&#xff0c;有时候通过bios根本找不到它的存在&#xff0c;以至于每次windows开机出现grub之后都要输入exit退出linux的引导之后才能使得电脑进入windows&#xff0c;这个有时会…

Python | Leetcode Python题解之第108题将有序数组转换为二叉搜索树

题目&#xff1a; 题解&#xff1a; class Solution:def sortedArrayToBST(self, nums: List[int]) -> TreeNode:def helper(left, right):if left > right:return None# 选择任意一个中间位置数字作为根节点mid (left right randint(0, 1)) // 2root TreeNode(nums…

纯血鸿蒙APP实战开发——边缓存边播放案例

介绍 OhosVideoCache是一个支持边播放边缓存的库&#xff0c;只需要将音视频的url传递给OhosVideoCache处理之后再设置给播放器&#xff0c; OhosVideoCache就可以一边下载音视频数据并保存在本地&#xff0c;一边读取本地缓存返回给播放器&#xff0c;使用者无需进行其他操作…

NDIS小端口驱动(五)

在需要的时候&#xff0c;我们也许需要NDIS微型端口程序信息&#xff0c;下面会从多个方面来讨论如何查询NDIS微型端口驱动。 查询无连接微型端口驱动程序 若要查询无连接微型端口驱动程序维护的 OID&#xff0c;绑定协议调用 NdisOidRequest 并传递 一个NDIS_OID_REQUEST 结…

Mac 安装 git

文章目录 前言一、介绍二、下载三、验证四、配置五、Git常用命令六、git提交和撤销工作流程代码提交和提交同步代码撤销和撤销同步 FAQ1.homebrew 下载解决方法一&#xff08;强烈推荐&#xff09;&#xff1a;解决方法二&#xff1a; 总结 前言 Git 是一个开源的分布式版本控…

LeetCode547省份数量

题目描述 有 n 个城市&#xff0c;其中一些彼此相连&#xff0c;另一些没有相连。如果城市 a 与城市 b 直接相连&#xff0c;且城市 b 与城市 c 直接相连&#xff0c;那么城市 a 与城市 c 间接相连。省份 是一组直接或间接相连的城市&#xff0c;组内不含其他没有相连的城市。给…

第十一章 文件及IO操作

第十一章 文件及IO操作 文件的概述及基本操作步骤 文件&#xff1a; 存储在计算机的存储设备中的一组数据序列就是文件不同类型的文件通过后缀名进行区分 文本文件&#xff1a;由于编码格式的不同&#xff0c;所占磁盘空间的字节数不同(例如GBK编码格式中一个中文字符占2字…

cesium绘制三角网可视化及mesh网格数据解析

可视化运行效果(水质污染扩散) 实现运行效果 术语 Mesh网格数据解析 Mesh&#xff08;网格&#xff09;在不同领域有不同的应用和定义。在计算机网络中&#xff0c;Mesh网络指的是一种无中心的网状结构&#xff0c;每个节点都与其他节点相连。而在3D计算机图形学中&#…

云原生Kubernetes: K8S 1.26版本 部署KubeSphere

目录 一、实验 1.环境 2.K8S 1.26版本部署HELM 3.K8S 1.26版本 部署KubeSphere 4.安装KubeSphere DevOps 二、问题 1.如何安装Zadig 2.扩展插件Zadig安装失败 3.calico 如何实现不同node通信 4.如何清除docker占用的磁盘空间 5.如何强制删除资源 6.namespace删除不…

宿舍管理系统--毕业设计

毕业设计&#x1f4bc;MD5加密&#x1f512;SSM框架&#x1f3a8;Layui框架&#x1f384; 实现功能 管理员的登录与登出 管理员,班级,学生,宿舍&#xff0c;卫生&#xff0c;访客各模块增删改查 个别模块关联查询 各个模块数据导出Excel 一些截图

[4]CUDA中的向量计算与并行通信模式

CUDA中的向量计算与并行通信模式 本节开始&#xff0c;我们将利用GPU的并行能力&#xff0c;对其执行向量和数组操作讨论每个通信模式&#xff0c;将帮助你识别通信模式相关的应用程序&#xff0c;以及如何编写代码 1.两个向量加法程序 先写一个通过cpu实现向量加法的程序如…

软件设计:基于 python 代码快速生成 UML 图

1. 官方文档 PlantUML Language Reference Guide Comate | 百度研发编码助手 百度 Comate (Coding Mate Powered by AI) 是基于文心大模型的智能代码助手&#xff0c;结合百度积累多年的编程现场大数据和外部优秀开源数据&#xff0c;可以生成更符合实际研发场景的优质代码。…

GBDT、XGBoost、LightGBM算法详解

文章目录 一、GBDT (Gradient Boosting Decision Tree) 梯度提升决策树1.1 回归树1.2 梯度提升树1.3 Shrinkage1.4 调参1.5 GBDT的适用范围1.6 优缺点 二、XGBoost (eXtreme Gradient Boosting)2.1 损失函数2.2 正则项2.3 打分函数计算2.4 分裂节点2.5 算法过程2.6 参数详解2.7…

oracle中insert all的用法

1、简述 使用insert into语句进行表数据行的插入&#xff0c;但是oracle中有一个更好的实现方式&#xff1a;使用insert all语句。 insert all语句是oracle中用于批量写数据的 。insert all分又为 无判断条件插入有判断条件插入有判断条件插入分为 Insert all when... 子句 …

利用 MongoDB Atlas 进行大模型语义搜索和RAG

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学. 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总合集&…

基于英飞凌BGT60LTR11AIP E6327芯片具低功耗的脉冲多普勒操作模式常用于汽车应用的雷达上

芯片特征&#xff1a; 60 GHz收发器MMIC&#xff0c;带一个发射器和一个接收器单元封装天线&#xff08;AIP&#xff09;&#xff08;6.73.30.56 mm3)低功耗的脉冲多普勒操作模式自主模式用于运动和运动方向的集成检测器运动检测信号的直接输出目标检测范围的15个可配置阈值检测…

Android14之Binder调试(二百一十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…