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

【Java基础】泛型

文章目录

  • 泛型
  • 一、概述
  • 二、泛型的使用
    • 1、类
    • 2、方法
    • 3、接口
  • 三、泛型通配符
    • 1、<?>
    • 2、<? extends T>
    • 3、<? super T>
  • 四、泛型的擦除
    • 1、泛型的擦除
    • 2、泛型边界的擦除
    • 3、无法实例化泛型类型

泛型

一、概述

泛型(Generic)是一种机制,允许你编写与数据类型无关的代码,增加代码的灵活性和可重用性。

  • 泛型在定义的时候不具体,使用的时候才变得具体。在使用的时候确定泛型的具体数据类型。

泛型的作用:

  1. 安全性:编译时检查类型,将运行时期的ClassCastException,转移到编译时期的编译失败。
  2. 灵活性:使类型参数化,可以预先地使用未知的类型,让设计的代码更通用灵活。
  3. 重用性:一个泛型类或方法可以处理多种数据类型,减少代码重复。
  4. 维护性:泛型代码通常更清晰,容易理解和维护。

注意事项:

  • 泛型只能在编译阶段起作用,到了运行阶段就会被擦除
  • 泛型只能是引用数据类型,不能是 基本数据类型。
  • 泛型在使用时指定实际的类型,如果不指定默认为Object类型。

二、泛型的使用

1、类

定义:类名之后

// 泛型一般用大写的单个字母表示,可以定义多个泛型,使用逗号分隔。
修饰符 class 类名<A, B, C> {}

使用:在类中使用,可以作为 实例方法 的 参数 和 返回值(静态方法不支持)

class Example<T> {// 作为实例方法的参数类型public void show(T t) {System.out.println(t);}// 作为实例方法的返回值类型public T get(int index) {return null;}// 静态方法 不能使用 类上定义的泛型// public static void test1(T t) {...}// public static T test2(int index) {...}
}

指定类型:创建对象时

public class Test {public static void main(String[] args) {// 在创建对象时,根据需要指定泛型的类型DataShow<String> ds = new DataShow<>();ds.show("Hello");  }
}

2、方法

定义:返回值之前

修饰符 <T> 返回值类型 方法名(T t) {}

使用:在方法内部使用

class Example {public static <T> void show(T t) {// 在方法内部使用System.out.println("t = " + t);}// 不同方法的泛型名称可以一致public static <T> void show2(T t) {}
}

指定类型:调用方法时,根据传参的类型

public class Test {public static void main(String[] args) {show(100);		// T -> Integershow("Hello");	// T -> String}
}

3、接口

定义:接口名之后

public interface 接口名<E> {}

使用:作为 接口方法 的 参数 或 返回值

public interface Example<T> {void method1(T t);T method2();
}

指定类型:

1、定义接口的实现类时,确定泛型的类型

public class ExampleChild1 implements Example<String>{@Overridepublic void method1(String s) {System.out.println(s);}@Overridepublic String method2() {return null;}
}

2、定义接口的实现类时,继续沿用泛型

public class ExampleChild2<T> implements Example<T> {@Overridepublic void method1(T t) {System.out.println(t);}@Overridepublic T method2() {return null;}
}

在创建接口的实现类对象时,确定泛型的类型

public class Test {public static void main(String[] args) {ExampleChild2<String> exampleChild2 = new ExampleChild2<>();exampleChild2.method1("hello");String str = exampleChild2.method2();}
}

三、泛型通配符

泛型通配符<?> ,常用于泛型方法和类中,帮助实现更加灵活和通用的类型操作。

1、<?>

<?>:表示任意类型,适用于我们不关心具体类型的场景。(只能使用Object类中的共性方法)

public void printList(List<?> list) {for (Object obj : list) {System.out.println(obj);}
}

使用举例

public class Test {public static void main(String[] args) {List<Integer> integerList = new ArrayList<>();integerList.add(1);integerList.add(2);// 使用泛型方法printList(integerList);}public static void printList(List<?> list) {for (Object obj : list) {System.out.println(obj);}}
}

2、<? extends T>

<? extends T>:表示 TT 的子类型,适用于读取操作。(可以使用父类T 中的公共方法)

public void processNumbers(List<? extends Number> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L;	 // Long extends Numbernumbers.add(a);  // error,Java 的泛型系统为了类型安全,不允许向这样的列表中添加特定类型的元素(除 null 外)。
}
public <T extends Number> void processNumbers(List<T> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L;	 // Long extends Numbernumbers.add(a);  // error
}

使用举例

public class Test {public static void main(String[] args) {List<Integer> integerList = new ArrayList<>();integerList.add(1);integerList.add(2);// 使用泛型方法printNumbers(integerList);}public static <T extends Number> void printNumbers(List<T> list) {for (T number : list) {System.out.println(number);}}
}

3、<? super T>

<? super T>:表示 TT 的父类型,适用于写入操作。

public void addNumbers(List<? super Integer> list) {list.add(1); // 可以安全地添加 Integer 类型的元素list.add(2); // 也可以添加其他 Integer 类型的元素
}
// 编译错误! `super` 只能用在 泛型方法 或 类中的方法参数 中来指定一个类型范围。
public <T super Integer> void addNumbers(List<T> list) {...}

使用举例

public class Test {public static void main(String[] args) {List<Number> numbers = new ArrayList<>();// 使用泛型方法addNumbers(numbers);System.out.println(numbers);}public static void addNumbers(List<? super Integer> list) {list.add(1);  // 可以添加 Integer 类型的对象list.add(2);  // 可以添加 Integer 类型的对象}
}

四、泛型的擦除

泛型的擦除是指,在编译期间,Java 编译器会将泛型信息擦除掉,泛型类型参数会被替换为其限定类型。

  • 默认情况下,泛型类型参数会被替换为 Object
  • 如果泛型有上限,如 T extends Number,擦除后会使用上限类型(Number)。

例如:

  • List<String>List<Integer> 在编译后都会被擦除为 List
  • List<T extends Number> 会擦除为 List<Number>

泛型擦除的主要目的是为了 兼容 Java 的早期版本 和 简化虚拟机的实现。

  • 泛型擦除将泛型类型转换为 Object 或其超类,从而使得 泛型代码 可以与 旧版本的 Java 代码 相互操作。
  • 泛型擦除意味着 泛型的具体类型(T)在字节码中不可见,保持向后兼容性的同时,避免对字节码格式进行重大修改。

但是,这也会导致一些泛型相关的信息在运行时不可用,需要在编写泛型代码时注意擦除造成的影响。

1、泛型的擦除

public class GenericMethodExample {// 泛型方法  在擦除后会变成 `print(Object data)` public <T> void print(T data) {System.out.println(data);}// 原始类型的方法 -> 编译错误!因为与擦除后的泛型方法冲突了public void print(Object data) {System.out.println(data);}
}
public class GenericMethodExample {// 泛型方法  在擦除后会变成 `print(Object data)` public <T> void print(T data) {System.out.println(data);}// 原始类型的方法 -> 编译通过!因为泛型默认擦除为 Object,这里是 String,重载public void print(String data) {System.out.println(data);}
}

2、泛型边界的擦除

public void processNumbers(List<? extends Number> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L;	 // Long extends Numbernumbers.add(a);  // error
}
  • List<T extends Number> 在编译后会被擦除为 List<Number>
public <T extends Number> void processNumbers(List<T> numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a = 1L;	 // Long extends Numbernumbers.add(a);  // error
}
  • 泛型参数 T 在运行时被擦除为 Number 类型。

3、无法实例化泛型类型

public class GenericInstantiationExample<T> {private T instance;public GenericInstantiationExample() {// 编译错误:无法直接实例化泛型类型// instance = new T(); // 错误}public GenericInstantiationExample(Class<T> clazz) {try {instance = clazz.getDeclaredConstructor().newInstance();} catch (Exception e) {e.printStackTrace();}}
}
  • new T() 在编译时会引发错误,因为 T 的实际类型在运行时未知。
  • 可以使用反射(通过传递 Class<T> 对象)来实例化对象。

相关文章:

【Java基础】泛型

文章目录 泛型一、概述二、泛型的使用1、类2、方法3、接口 三、泛型通配符1、<?>2、<? extends T>3、<? super T> 四、泛型的擦除1、泛型的擦除2、泛型边界的擦除3、无法实例化泛型类型 泛型 一、概述 泛型&#xff08;Generic&#xff09;是一种机制&a…...

STL-vector练习题

118. 杨辉三角 思路&#xff1a; 杨辉三角有以下性质使我们要用到的&#xff1a; ● 每行数字左右对称&#xff0c;由 1 开始逐渐变大再变小&#xff0c;并最终回到 1。 ● 第 n 行&#xff08;从 0 开始编号&#xff09;的数字有 n1 项&#xff0c;前 n 行共有 2n(n1)个数。…...

Leetcode 165. 比较版本号(Medium)

给你两个 版本号字符串 version1 和 version2 &#xff0c;请你比较它们。版本号由被点 . 分开的修订号组成。修订号的值 是它 转换为整数 并忽略前导零。 比较版本号时&#xff0c;请按 从左到右的顺序 依次比较它们的修订号。如果其中一个版本字符串的修订号较少&#xff0c…...

Android 12 Launcher3 去掉Hotseat

1.概述 在12.0 产品定制化开发中 由产品需求Launcher3 页面布局的原因&#xff0c;要求Launcher3 需要去掉Hotseat 不显示Hotseat下面几个图标&#xff0c;而做满屏app的显示&#xff0c;从而达到美观的效果&#xff0c;下面就来分析去掉Hotseat从而实现这个功能 2.Launcher3 …...

Nginx实用篇:实现负载均衡、限流与动静分离

Nginx实用篇&#xff1a;实现负载均衡、限流与动静分离 | 原创作者/编辑&#xff1a;凯哥Java | 分类&#xff1a;Nginx学习系列教程 Nginx 作为一款高性能的 HTTP 服务器及反向代理解决方案&#xff0c;在互联网架构中扮演着至关重要的角色。它…...

python | Python中的类多态:方法重写和动态绑定

本文来源公众号“python”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;Python中的类多态&#xff1a;方法重写和动态绑定 多态&#xff08;Polymorphism&#xff09;是面向对象编程的核心特性之一&#xff0c;它允许同一接口在…...

Rust编写Windows服务

文章目录 Rust编写Windows服务一&#xff1a;Windows服务程序大致原理二&#xff1a;Rust中编写windows服务三&#xff1a;具体实例 Rust编写Windows服务 编写Windows服务可选语言很多, 其中C#最简单。本着练手Rust语言&#xff0c;尝试用Rust编写一个服务。 一&#xff1a;Win…...

MATLAB 从 R2024B 开始支持树莓派 5

树莓派&#xff08;Raspberry Pi&#xff09;系列是一系列基于单板计算机的微型电脑&#xff0c;由英国的树莓派基金会于 2012 年开始发布。它的目标是提供一个低成本、易于学习和玩耍的平台&#xff0c;用于教育和初学者学习计算机科学和编程。 目前市面上&#xff0c;最新最…...

MiniBlogum项目简介

MiniBlogum项目简介 文章目录 MiniBlogum项目简介一、引言二、技术栈与开发环境三、主要功能&#xff08;一&#xff09;用户注册与登录&#xff08;二&#xff09;查看当前登录用户/作者头像、昵称、Gitee仓库地址&#xff08;三&#xff09;查看博客列表&#xff08;四&#…...

如何用 OBProxy 实现 OceanBase 的最佳路由策略

引言 OBProxy&#xff0c;即OceanBase Database Proxy&#xff0c;也简称为ODP&#xff0c;是 OceanBase数据库的专属服务代理。通过应用OBProxy&#xff0c;由后端OceanBase集群的分布式特性所带来的复杂性得以屏蔽&#xff0c;从而使得访问分布式数据库的体验如同访问单机数…...

new/delete和malloc/free到底有什么区别

new和malloc 文章目录 new和malloc前言一、属性上的区别二、使用上的区别三、内存位置的区别四、返回类型的区别五、分配失败的区别六、扩张内存的区别七、系统调度过程的区别总结 前言 new和malloc的知识点&#xff0c;作为一个嵌入式工程师是必须要了解清楚的。new和malloc的…...

Flutter启动无法运行热重载

当出现这种报错时&#xff0c;大概率是flutter的NO_Proxy出问题。 请忽略上面的Android报错因为我做的是windows开发这个也就不管了哈&#xff0c;解决下面也有解决报错的命令大家执行一下就行。 着重说一下Proxy的问题&#xff0c; 我们看到提示NO_PROXY 没有设置。 这个时候我…...

CSS调整背景

一、设置背景颜色 通过 background-color 属性指定&#xff0c;值可以是十六进制 #ffffff&#xff0c;也可以是rgb(0, 255, 255)&#xff0c;或是颜色名称 "red" div {background-color: red; /* 通过颜色名称设置 */background-color: #ff0000; /* 通过十六进制设…...

FinalShell连接Linux服务器并解决反复输入密码问题

FinalShell是一款由国人开发的SSH客户端工具&#xff0c;它支持多平台&#xff0c;包括Windows、Mac OS X和Linux。FinalShell主要用于一体化服务器管理&#xff0c;它不仅是一个SSH客户端&#xff0c;还具备强大的开发和运维功能&#xff0c;能够充分满足开发和运维的需求。 本…...

实用类工具!分享6款AI论文一键生成器免费8000字

在当前的学术研究和写作领域&#xff0c;AI论文生成工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。千笔-AIPassPaper是一款备受推荐的AI论文一键生成器。 千笔-AIPassPaper是一个一站式…...

vue使用TreeSelect设置带所有父级节点的回显

Element Plus的el-tree-select组件 思路&#xff1a; 选中节点时&#xff0c;给选中的节点赋值 pathLabel&#xff0c;pathLabel 为函数生成的节点名字拼接&#xff0c;数据源中不包含。 在el-tree-select组件中设置 props“{ label: ‘pathLabel’ }” 控制选中时input框中回…...

智能机巢+无人机:自动化巡检技术详解

智能机巢与无人机的结合&#xff0c;在自动化巡检领域展现出了巨大的潜力和优势。以下是对这一技术的详细解析&#xff1a; 一、智能机巢概述 智能机巢&#xff0c;也被称为无人机机场或无人机机巢&#xff0c;是专门为无人机提供停靠、充电、维护等服务的智能化设施。它不仅…...

摩托车加装车载手机充电usb方案/雅马哈USB充电方案开发

长途骑行需要给手机与行车记录仪等设备供电&#xff0c;那么&#xff0c;加装USB充电器就相继在两轮电动车上应用起来了。摩托车加装usb充电方案主要应用于汽车、电动自行车、摩托车、房车、渡轮、游艇等交通工具。提供电动车USB充电器方案/摩托车加装usb充电方案/渡轮加装usb充…...

进阶岛 任务3: LMDeploy 量化部署进阶实践

进阶岛 任务3&#xff1a; LMDeploy 量化部署进阶实践 任务&#xff1a;https://github.com/InternLM/Tutorial/blob/camp3/docs/L2/LMDeploy/task.md 使用结合W4A16量化与kv cache量化的internlm2_5-1_8b-chat模型封装本地API并与大模型进行一次对话&#xff0c;作业截图需包…...

vue 使用jszip,file-saver下载压缩包,自定义文件夹名,文件名打包下载为zip压缩包文件,全局封装公共方法使用。

记录一下后台管理全局封装一个压缩包下载方法&#xff0c;文件夹名自定义&#xff0c;文件名自定义&#xff0c;压缩包名自定义。 安装必要的库 npm install jszip npm install file-saver自定义一个公共方法全局注入 页面使用 /** 下载按钮操作 */handleDownload() {const i…...

新手友好!FUTURE POLICE语音解构模型快速入门:搭建智能音频处理流水线

新手友好&#xff01;FUTURE POLICE语音解构模型快速入门&#xff1a;搭建智能音频处理流水线 1. 认识FUTURE POLICE语音解构模型 1.1 什么是语音解构技术 想象一下&#xff0c;你有一段会议录音&#xff0c;想要快速找到某个关键词出现的确切时间点。传统语音识别只能告诉你…...

终极指南:如何使用Orchestrator Raft模式构建无单点故障的MySQL高可用系统

终极指南&#xff1a;如何使用Orchestrator Raft模式构建无单点故障的MySQL高可用系统 【免费下载链接】orchestrator MySQL replication topology management and HA 项目地址: https://gitcode.com/gh_mirrors/or/orchestrator Orchestrator是一款强大的MySQL复制拓扑…...

sing-box常见问题排查:99%的用户都会遇到的坑

sing-box常见问题排查&#xff1a;99%的用户都会遇到的坑 引言 sing-box作为一款功能强大的通用代理平台&#xff08;The universal proxy platform&#xff09;&#xff0c;在使用过程中难免会遇到各种问题。本文将针对用户最常遇到的配置错误、连接失败、日志分析等问题提供…...

hello-uniapp技术债务管理:平衡开发速度与代码质量的终极指南 [特殊字符]

hello-uniapp技术债务管理&#xff1a;平衡开发速度与代码质量的终极指南 &#x1f680; 【免费下载链接】hello-uniapp uni-app框架演示示例 项目地址: https://gitcode.com/gh_mirrors/he/hello-uniapp 在快速发展的移动应用开发领域&#xff0c;hello-uniapp作为uni-…...

八大网盘直链下载神器:告别客户端依赖,解锁高速下载新体验

八大网盘直链下载神器&#xff1a;告别客户端依赖&#xff0c;解锁高速下载新体验 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国…...

Jimeng LoRA自动化测试方案:脚本驱动多Epoch批量生成+效果评分体系

Jimeng LoRA自动化测试方案&#xff1a;脚本驱动多Epoch批量生成效果评分体系 1. 项目简介&#xff1a;一个为LoRA进化史量身定做的“显微镜” 如果你训练过LoRA模型&#xff0c;尤其是像Jimeng&#xff08;即梦&#xff09;这样风格独特的系列&#xff0c;一定遇到过这个头疼…...

OFA图像语义蕴含Web应用5分钟部署教程:图文匹配AI一键搭建

OFA图像语义蕴含Web应用5分钟部署教程&#xff1a;图文匹配AI一键搭建 1. 项目简介与核心价值 OFA&#xff08;One For All&#xff09;图像语义蕴含模型是阿里巴巴达摩院研发的多模态深度学习系统&#xff0c;能够智能分析图像内容与文本描述之间的逻辑关系。这个Web应用将强…...

OpenClaw配置备份方案:Qwen3.5-9B-AWQ-4bit迁移到新设备

OpenClaw配置备份方案&#xff1a;Qwen3.5-9B-AWQ-4bit迁移到新设备 1. 为什么需要完整的配置迁移方案 上周我的主力开发机突然硬盘故障&#xff0c;导致所有OpenClaw配置丢失。重新搭建环境时发现&#xff0c;单纯备份openclaw.json远远不够——飞书机器人授权失效、硬件指纹…...

apache-dolphinscheduler-3.4.1调度器配置虚拟机

1、下载文件3.4.1下载安装包https://mirrors.tuna.tsinghua.edu.cn/apache/dolphinscheduler/3.4.1/ 2、传到虚拟机/home/spark2下 3、解压并重命名 4、初始化 MySQL 数据库 &#xff08;1&#xff09;启动 MySQL 服务 &#xff08;2&#xff09;登录 MySQL&#xff08;输入 r…...

从PX4的FRD到Mavros的FLU:手把手教你正确配置`setpoint_raw/local`话题发布无人机目标点

从PX4的FRD到Mavros的FLU&#xff1a;无人机坐标系转换实战指南 当你在ROS环境下通过Mavros向PX4飞控发送位置指令时&#xff0c;是否遇到过无人机朝完全相反方向飞行的情况&#xff1f;这种"方向错乱"的根源往往在于坐标系理解的偏差。本文将彻底解开PX4与Mavros之间…...