【JavaSE】Java进阶知识一(泛型详解,包括泛型方法,协变,逆变,擦除机制)

news2024/9/28 19:15:40

目录

泛型

1. 什么是泛型

2.泛型方法

3.通配符上界(泛型的协变)

4.通配符下界(泛型的逆变)

5.泛型的编译(擦除机制)


泛型

        泛型:就是让一个类能适用于多个类型,就是在封装数据结构时能让封装的类型被各种类型使用所以引入了泛型的概念,虽然有了泛型,什么数据都可以放,但是更多情况下我们还是希望他只能持有一种数据类型。所以,泛型的主要目的:指定当前的容器,要持有什么类型的对象,让编译器去做检查。

1. 什么是泛型

语法格式如下:

泛型类<类型实参>变量名;//定义一个泛型类引用

new 泛型类<类型实参>(构造方法实参);//实例化一个泛型类对象

一般用<T>作为占位符 ,表示当前类是一个泛型类。Java中的泛型参数只能是引用类型,不能是基本类型,这与Java的泛型擦出机制有关。

 实例:

MyArray<Integer> list = new MyArray<Integer>();

*裸类型(Raw Type)      (这是一个泛型类但没有带着类型实参) 

MyArray list = new MyArray();

裸类型是为了兼容老版本的API保留机制,我们不要轻易使用。 

2.泛型方法

 泛型方法:定义一个泛型方法,我们需要在方法返回值前使用尖括号声明一个或多个泛型参数然在方法中就可以用到声明的泛型参数了,调用泛型方法时,我们不需要手动写出类型,编译器会根据你的调用,自动推导出具体类型。

静态泛型方法:泛型类有一个局限,静态方法和静态属性访问不了类上定义的泛型参数,静态泛型方法的定义和使用与普通泛型方法一致。

泛型类和泛型方法的使用场景:

当泛型参数需要在多个方法或成员属性间扭转,就使用泛型类,比如:集合。

当泛型参数只需要作用于某个方法,那就使用泛型方法。

3.通配符上界(泛型的协变)

泛型类型是具有不变性的,比如下面代码就是错误的:

Arraylist<Object> objectList;
ArrayList<String> stringList = new ArrayList<>();
objectList=stringList//这里会报错

objectList.add(new Shit());
String str = stringList.get(0);
//因为我们无法将一个object对象转化为string对象,所以在编译层面上面的赋值就会直接报错

 为了让泛型变得更灵活,Java引入了通配符:?,通过下面的代码来给大家介绍一下通配符的作用:

在不使用通配符时,因为泛型的不变性,下面这段代码会出现问题,就使代码非常不灵活。

public static double sum(List<Number> list){
   double result =0;
   for(Number number : list){
        result += number.doubleValue();
   }
    return result;
}

List<Double> doubleList = new ArrayList<>();
sum(doubleList)//这里会报错

我们可以使用通配符上界(?:extends T)来使代码更灵活

public static double sum(List<? extends Number> list){
   double result =0;
   for(Number number : list){
        result += number.doubleValue();
   }
    return result;
}

List<Double> doubleList = new ArrayList<>();
sum(doubleList)

这种写法也被叫做泛型的协变 。

4.通配符下界(泛型的逆变)

我们还可以使用通配符下界(?:super T)来使代码变得灵活,代码实例如下:

class Food {
}
class Fruit extends Food {
}
class Apple extends Fruit {
}
class Plate<T> {
private T plate ;
public T getPlate() {
return plate;
}
public void setPlate(T plate) {
this.plate = plate;
}
}
public class TestDemo {
public static void main(String[] args) {
Plate<Fruit> plate1 = new Plate<>();
plate1.setPlate(new Fruit());
fun(plate1);
Plate<Food> plate2 = new Plate<>();
plate2.setPlate(new Food());
fun(plate2);
}
public static void fun(Plate<? super Fruit> temp){
// 此时可以修改!!添加的是Fruit 或者Fruit的子类
temp.setPlate(new Apple());//这个是Fruit的子类
temp.setPlate(new Fruit());//这个是Fruit的本身
//Fruit fruit = temp.getPlate(); 不能接收,这里无法确定是哪个父类
System.out.println(temp.getPlate());//只能直接输出
}
}

通配符的优缺点:

协变:放宽了对子类类型的泛型约束,但是缺点是不能对调用的参数进行写入数据只能进行读取数据。

逆变:放宽了对父类类型的泛型约束,但是缺点是不能对参数进行读取数据,只能写入数据。

5.泛型的编译(擦除机制)

擦除机制的实质就是,在编译阶段,Java的泛型类型可能是ArrayList<Integer>但是在java文件编译成字节码的过程中,泛型参数部分就被擦出了(泛型类,泛型方法的参数全部被替换成它的第一个上界或者顶级父类Object),在class文件中,无论参数是什么,JVM实际执行的代码类型其实是ArrayList<Object>类型,这也就引出了很多问题如下:

  1. 泛型参数只能是引用类型而不能是基本数据类型,因为基本数据类型无法被擦除成Object。
  2. 不能使用instanceof关键字进行泛型类型检测,因为在运行时所以的泛型类型都是裸类型。
  3. 泛型类型无法实例化类型参数T a=new T(),因为在运行时无法确定T的具体类型,也不知道T是否存在无参构造器。
  4. 无法实例化泛型数组T[] arry =new T[2];因为泛型最后都被擦除成Object数组,在使用时很容易发生类型转化异常,比如object转化不成string。

擦除机制是Java为了引入泛型这个语法而不得不做出的妥协之举,泛型语法是JDK5之后引入的,为了兼容老版本,不得不在编译阶段将泛型擦除成裸类型。但是在其他语言中,泛型的使用会非常自然且简单安全,在编写代码是我们要了解泛型擦除机制,否则可能会引发很多不必要的异常。

类型擦除是指在运行时对于JVM而言泛型参数被擦除掉了,并不代表泛型信息消失了,才class文件中泛型信息被以其他方式进行保存,我们依然可以在运行时通过反射的手段进行泛型类型检测。

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

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

相关文章

前端---vscode 的基本使用

1. vscode 的基本介绍 全拼是 Visual Studio Code (简称 VS Code) 是由微软研发的一款免费、开源的跨平台代码编辑器&#xff0c;目前是前端(网页)开发使用最多的一款软件开发工具。 2. vscode 的安装 下载网址: Download Visual Studio Code - Mac, Linux, Windows选择对应…

PyQt5和Qt designer的详细安装教程

Qt designer界面和所有组件功能的详细介绍参考&#xff1a;https://blog.csdn.net/qq_43811536/article/details/135186862?spm1001.2014.3001.5501 目录 0. 写在前面1. Anaconda创建虚拟环境2. 安装PyQt5和Qt designer3. 测试安装成功 0. 写在前面 Qt Designer是Qt提供的一种…

Tiny Object Detection

文章目录 RFLA: Gaussian Receptive Field based Label Assignment for Tiny Object Detection&#xff08;ECCV2022&#xff09;Dynamic Coarse-to-Fine Learning for Oriented Tiny Object Detection&#xff08;CVPR2023&#xff09;TOD-CMLNN&#xff08;2023&#xff09; …

RK3568平台开发系列讲解(Linux系统篇)Linux 热拔插机制 mdev的使能

🚀返回专栏总目录 文章目录 一、什么是热插拔二、热插拔的机制三、mdev的开启沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 Linux 热拔插。 一、什么是热插拔 热插拔是指在设备运行的情况下,能够安全地插入或拔出硬件设备,而无需关闭或重启系统。这意…

关于Nacos各日志以及解决Nacos中疯狂输出日志的问题

目录 前言1. 各日志内容2. 日志解析2.1 服务端日志2.2 客户端日志 前言 越来越发觉硬盘不够用&#xff0c;发现是运行了2年的Nacos中存了很多log日志&#xff0c;具体如下&#xff1a; 于是得了解下各个日志中的作用&#xff0c;防止不必要的输出占用硬盘空间&#xff01; …

Web前端-JavaScript(Dom高级)

文章目录 1.1 自定义属性操作1.1.1 获取属性值1.1.2 设置属性值1.1.3 移除属性值1.1.4 案例一 1.2 节点操作1.2.1 节点概述1.2.2 节点层级1.2.3 父级节点1.2.4 子节点1.2.5 兄弟节点1.2.6 创建节点1.2.7 添加节点1.2.8 删除节点1.2.9 案例二1.2.10 创建元素的三种方式(了解) 1.…

LabVIEW在横向辅助驾驶系统开发中的应用

LabVIEW在横向辅助驾驶系统开发中的应用 随着横向辅助驾驶技术的快速发展&#xff0c;越来越多的研究致力于提高该系统的效率和安全性。项目针对先进驾驶辅助系统&#xff08;ADAS&#xff09;中的横向辅助驾驶进行深入研究。在这项研究中&#xff0c;LabVIEW作为一个强大的系…

GEE数据集——USGS全球地震数据集

美国地质勘探局全球地震数据集 美国地质调查局地震灾害计划 (EHP) 提供全面的地震数据集&#xff0c;为全球监测、研究和地震防备提供宝贵资源。该数据集包含来自各种来源的地震信息&#xff0c;包括地震台、卫星图像和地面观测。持续更新&#xff0c;截至 2023 年 10 月 10 日…

mysql原理--连接查询的成本

1.准备工作 连接查询至少是要有两个表的&#xff0c;只有一个 single_table 表是不够的&#xff0c;所以为了故事的顺利发展&#xff0c;我们直接构造一个和 single_table 表一模一样的 single_table2 表。为了简便起见&#xff0c;我们把 single_table 表称为 s1 表&#xff0…

模糊测试:使用随机输入破坏事物

模糊测试&#xff1a;使用随机输入破坏事物 一个简单的模糊器模糊测试外部程序创建输入文件调用外部程序长时间运行的模糊测试 模糊测试器的发现缓冲区溢出缺少错误检查 我们将从最简单的测试生成技术之一开始&#xff0c;随机文本生成&#xff08;也称为模糊测试&#xff09;的…

Spring Cloud Gateway官方文档学习笔记

Spring Cloud Gateway官方文档学习笔记 前言 基础知识&#xff1a;API网关基础知识总结面试题&#xff1a;Spring Cloud Gateway夺命连环10问&#xff1f; 何为网关&#xff1f; 什么是网关&#xff1f;理解成火车站的检票口&#xff0c;统一 检票 网关优点&#xff1a; 统…

C#上位机与欧姆龙PLC的通信05---- HostLink协议

1、介绍 Hostlink协议是欧姆龙PLC与上位机链接的公开协议。上位机通过发送Hostlink命令&#xff0c;可以对PLC进行I/O读写、可以对PLC进行I/O读写、改变操作模式、强制置位/复位等操作。由于是公开协议&#xff0c;即便是非欧姆龙的上位设备&#xff08;软件&#xff09;&…

王者荣耀展示

..在写代码前要创建这些文件夹&#xff0c;并储存图片 代码 package com.sxt; import javax.swing.*; import java.awt.*; public class Background extends GameObject { public Background(GameFrame gameFrame) { super(gameFrame); // TODO Aut…

第5章 散列

我们在第4章讨论了查找树ADT&#xff0c;它允许对一组元素进行各种操作。本章讨论散列表(hash table)ADT&#xff0c;不过它只支持二叉查找树所允许的一部分操作。 散列表的实现常常叫作散列(hashing)。散列是一种以常数平均时间执行插入、删除和查找的技术。但是&#xff0c;那…

运维大模型探索之 Text2PromQL 问答机器人

作者&#xff1a;陈昆仪&#xff08;图杨&#xff09; 大家下午好&#xff0c;我是来自阿里云可观测团队的算法工程师陈昆仪。今天分享的主题是“和我交谈并获得您想要的PromQL”。今天我跟大家分享在将AIGC技术运用到可观测领域的探索。 今天分享主要包括5个部分&#xff1a;…

【Linux系统基础】(3)在Linux上部署运维监控Zabbix和Grafana

目录 运维监控Zabbix部署简介安装安装前准备 - Mysql安装Zabbix Server 和 Zabbix Agenta. 安装Zabbix yum库b. 安装Zabbix Server、前端、Agentc. 初始化Mysql数据库d. 为Zabbix Server配置数据库e. 配置Zabbix的PHP前端 配置zabbix 前端&#xff08;WEB UI&#xff09; 运维监…

学习在UE中通过Omniverse实现对USD文件的Live-Sync(实时同步编辑)

目标 前一篇 学习了Omniverse的一些基础概念。本篇在了解这些概念的基础上&#xff0c;我想体验下Omniverse的一些具体的能力&#xff0c;特别是 Live-Sync (实时同步) 相关的能力。 本篇实践了使用Omniverse的力量在UE中建立USD文件的 Live-Sync 编辑。由于相关的知识我是从…

将Go语言开发的Web程序部署到K8S

搭建K8S基础环境 如果已经有K8S环境的同学可以跳过&#xff0c;如果没有&#xff0c;推荐你看看我的《Ubuntu22加Minikue搭建K8S环境》&#xff0c;课程目录如下&#xff1a; Ubuntu22安装Vscode 下载&#xff1a;https://code.visualstudio.com/Download 安装命令&#…

Unity之DOTweenPath轨迹移动

Unity之DOTweenPath轨迹移动 一、介绍 DOTweenPath二、操作说明1、Scene View Commands2、INfo3、Tween Options4、Path Tween Options5、Path Editor Options&#xff1a;轨迹编辑参数&#xff0c;就不介绍了6、ResetPath&#xff1a;重置轨迹7、Events&#xff1a;8、WayPoin…

ioDraw AI:思维导图、流程图、序列图、类图、饼图,一应俱全

前言 在信息爆炸的时代&#xff0c;我们每天接收着大量的信息&#xff0c;如何高效地整理和呈现这些信息成为了一项重要的挑战。思维导图作为一种可视化思维工具&#xff0c;能够帮助我们快速构建和整理复杂的信息结构&#xff0c;便于我们理解和记忆。ioDraw AI绘图工具正是基…