Java 泛型使用教程

简介

Java 泛型是 JDK 5 引入的一项特性,它提供了编译时类型安全检测机制,允许在编译时检测出非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

泛型的好处:

  • 编译期检查类型安全

  • 避免强制类型转换(cast

  • 代码更通用,更易重用

泛型的基本使用

泛型类
public class Box<T> {private T content;public void set(T content) {this.content = content;}public T get() {return content;}
}

使用:

Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get(); // 无需强转
泛型方法
public class Util {public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}
}

使用:

String[] arr = {"A", "B", "C"};
Util.printArray(arr);
泛型接口
public interface Converter<F, T> {T convert(F from);
}public class StringToIntegerConverter implements Converter<String, Integer> {public Integer convert(String from) {return Integer.parseInt(from);}
}

泛型中的通配符:?

? 通配符

表示任意类型:

public void printList(List<?> list) {for (Object item : list) {System.out.println(item);}
}
? extends T(上界通配符)

表示 TT 的子类(只读,不能写):

public void printNumbers(List<? extends Number> list) {for (Number num : list) {System.out.println(num);}
}

不能添加元素:

list.add(10); // ❌ 报错
? super T(下界通配符)

表示 TT 的父类(可以写入,但取出只能当作 Object):

public void addNumbers(List<? super Integer> list) {list.add(10); // ✅ OK
}

类型擦除(Type Erasure)

泛型在编译后会被擦除,JVM 不知道泛型类型,全部变成 Object

List<String> list = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list.getClass() == list2.getClass()); // true

正因如此:

  • 不能使用 new T()

  • 不能使用 T.class

  • 不能判断 instanceof T

常见的泛型类库例子

  • List<T>:存储 T 类型的集合

  • Map<K, V>:泛型键值对

  • Optional<T>:包装返回值

  • Comparable<T>:排序比较接口

  • Function<T, R>:函数式接口

  • Callable<T>:异步任务的返回类型

  • Future<T>:异步计算的结果

进阶技巧

泛型数组不允许:
List<String>[] lists = new List<String>[10]; // ❌ 编译错误
泛型静态方法必须声明 <T>
public static <T> void print(T value) {System.out.println(value);
}

实际项目中 Java 泛型的用法大全

通用返回封装类(统一 API 响应格式)
public class Result<T> {private int code;private String message;private T data;public Result(int code, String message, T data) {this.code = code;this.message = message;this.data = data;}public static <T> Result<T> success(T data) {return new Result<>(200, "Success", data);}public static <T> Result<T> fail(String message) {return new Result<>(500, message, null);}// getter/setter omitted
}
通用分页结果类
public class PageResult<T> {private List<T> records;private long total;public PageResult(List<T> records, long total) {this.records = records;this.total = total;}
}

结合 Spring 使用泛型的示例

通用 Service 接口
public interface BaseService<T, ID> {T findById(ID id);List<T> findAll();T save(T entity);void deleteById(ID id);
}
抽象 Service 实现类
public abstract class AbstractBaseService<T, ID> implements BaseService<T, ID> {@Autowiredprotected JpaRepository<T, ID> repository;@Overridepublic T findById(ID id) {return repository.findById(id).orElse(null);}@Overridepublic List<T> findAll() {return repository.findAll();}@Overridepublic T save(T entity) {return repository.save(entity);}@Overridepublic void deleteById(ID id) {repository.deleteById(id);}
}
具体 Service
@Service
public class UserService extends AbstractBaseService<User, Long> {// 可以扩展额外业务逻辑
}

Java 泛型 与 C#.net 泛型比较

Java 泛型 与 C# (.NET) 泛型有很多相似之处,C# 泛型的设计部分参考了 Java。但它们在类型擦除、协变/逆变、约束、运行时行为等方面有显著的不同。

特性Java 泛型C# (.NET) 泛型
类型擦除是(编译期擦除)否(保留类型信息)
运行时可反射获取泛型类型
基本类型支持不直接支持(需使用包装类如 Integer支持,例如 List<int>
泛型约束限制(只能 extends,不支持多个约束)强大(支持 where T : class, new(), 多个接口)
协变/逆变支持通过通配符 ? extends/super直接使用 out/in 关键字
泛型数组不支持(如 new T[] 编译错误)支持
泛型方法支持支持
类型擦除 vs 保留类型
  • Java
List<String> list = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
System.out.println(list.getClass() == intList.getClass()); // true

Java 在编译时擦除了泛型信息,List<String>List<Integer> 其实是同一个字节码类。

  • C#
List<string> list = new List<string>();
List<int> intList = new List<int>();
Console.WriteLine(list.GetType() == intList.GetType()); // false

C# 会为不同泛型参数生成不同的类实例,因此保留类型信息。

泛型约束
  • Java
public class Repository<T extends BaseEntity> {public void save(T entity) { }
}
  • C#
public class Repository<T> where T : BaseEntity, new() {public void Save(T entity) { }
}

C# 支持更丰富的泛型约束,例如要求是引用类型 class、值类型 struct、必须有无参构造函数 new() 等。

协变与逆变(Covariance & Contravariance)
  • Java 使用通配符
List<? extends Number> numbers;  // 只能读取,不能添加
List<? super Integer> integers;  // 只能添加 Integer
  • C# 使用 in / out
interface ICovariant<out T> { }
interface IContravariant<in T> { }

C# 在接口中用 in/out 明确支持协变逆变,且更强大、更类型安全。

泛型数组
  • Java
T[] array = new T[10]; // 编译错误
  • C#
T[] array = new T[10]; // 合法
基本类型泛型
  • Java
List<int> list = new ArrayList<>(); // 编译错误
List<Integer> list = new ArrayList<>(); // 正确
  • C#
List<int> list = new List<int>(); // 正确,泛型支持值类型
总结
特性JavaC#
类型安全✔️✔️
灵活性❌(类型擦除限制)✔️(运行时保留泛型)
泛型数组✔️
基本类型支持❌(需包装)✔️
泛型约束一般强大
协变逆变复杂、通配符语法简洁、原生支持
性能需装箱无装箱(对值类型更快)

协变逆变详解

协变(Covariance)和逆变(Contravariance)是泛型类型系统中用于处理子类和父类之间的泛型关系的重要机制。

Java 的协变(Covariant)与逆变(Contravariant)

Java 使用 通配符(wildcards) 来支持:

协变(? extends T) — 只读

  • 意思是:某个未知类型是 T 的子类

  • 常用于“只能读”的场景

public void readAnimals(List<? extends Animal> animals) {for (Animal animal : animals) {System.out.println(animal);}
}

可以传入 List<Cat>、List<Dog> 或 List<Animal>,但不能添加新元素。

animals.add(new Cat()); // ❌ 编译错误

逆变(? super T) — 只写

  • 意思是:某个未知类型是 T 的父类

  • 常用于“只能写”的场景

public void addCats(List<? super Cat> cats) {cats.add(new Cat());     // ✅ 合法// cats.add(new Animal()); // ❌ 不安全
}

可以传入 List<Cat>、List<Animal>、List<Object>,但不能安全地读取具体类型:

Object obj = cats.get(0); // 只能作为 Object 使用
C# 中的协变与逆变
  • C# 协变(out)
interface IReadOnlyList<out T> {T Get(int index);
}IReadOnlyList<Animal> animals = new List<Cat>(); // ✅ 协变成功
  • C# 逆变(in)
interface IWriter<in T> {void Write(T value);
}IWriter<Cat> writer = new AnimalWriter(); // ✅ 逆变成功
完整示例:协变 & 逆变
import java.util.*;class Animal { }
class Cat extends Animal { }
class Dog extends Animal { }public class VarianceDemo {public static void main(String[] args) {List<Cat> cats = new ArrayList<>();cats.add(new Cat());readAnimals(cats); // ✅ 协变addCats(cats);     // ✅ 逆变}// 协变:读取public static void readAnimals(List<? extends Animal> animals) {for (Animal a : animals) {System.out.println("Animal: " + a);}// animals.add(new Dog()); // ❌ 编译错误}// 逆变:写入public static void addCats(List<? super Cat> animals) {animals.add(new Cat()); // ✅}
}
总结
特性协变逆变
Java 关键字? extends T? super T
C# 关键字out Tin T
适合场景读取数据写入数据
是否可写
是否可读❌(只能当 Object)

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

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

相关文章

Leetcode - 周赛446

目录 一、3522. 执行指令后的得分二、3523. 非递减数组的最大长度三、3524. 求出数组的 X 值 I四、3525. 求出数组的 X 值 II 一、3522. 执行指令后的得分 题目链接 本题就是一道模拟题&#xff0c;代码如下&#xff1a; class Solution {public long calculateScore(String…

【更新完毕】2025泰迪杯数据挖掘竞赛A题数学建模思路代码文章教学:竞赛论文初步筛选系统

完整内容请看文末最后的推广群 基于自然语言处理的竞赛论文初步筛选系统 基于多模态分析的竞赛论文自动筛选与重复检测模型 摘要 随着大学生竞赛规模的不断扩大&#xff0c;参赛论文的数量激增&#xff0c;传统的人工筛选方法面临着工作量大、效率低且容易出错的问题。因此&…

计算机视觉与深度学习 | RNN原理,公式,代码,应用

RNN(循环神经网络)详解 一、原理 RNN(Recurrent Neural Network)是一种处理序列数据的神经网络,其核心思想是通过循环连接(隐藏状态)捕捉序列中的时序信息。每个时间步的隐藏状态 ( h_t ) 不仅依赖当前输入 ( x_t ),还依赖前一时间步的隐藏状态 ( h_{t-1} ),从而实现…

AI速读:解锁LLM下Game Agent的奇妙世界

在 AI 浪潮中&#xff0c;大语言模型&#xff08;LLMs&#xff09;正重塑游戏智能体格局。想知道基于 LLMs 的游戏智能体如何运作&#xff0c;在各类游戏中有何惊艳表现&#xff0c;未来又将走向何方&#xff1f; 大型语言模型&#xff08;LLMs&#xff09;的兴起为游戏智能体的…

【每日八股】复习计算机网络 Day3:TCP 协议的其他相关问题

文章目录 昨日内容复习TCP 的四次挥手&#xff1f;TCP 为什么要四次挥手&#xff1f;在客户端处于 FIN_WAIT_2 状态时&#xff0c;如果此时收到了乱序的来自服务端的 FIN 报文&#xff0c;客户端会如何处理&#xff1f;何时进入 TIME_WAIT 状态&#xff1f;TCP 四次挥手丢了怎么…

学习笔记十五——rust柯里化,看不懂 `fn add(x) -> impl Fn(y)` 的同学点进来!

&#x1f9e0; Rust 柯里化从零讲透&#xff1a;看不懂 fn add(x) -> impl Fn(y) 的同学点进来&#xff01; &#x1f354; 一、什么是柯里化&#xff1f;先用一个超好懂的生活比喻 假设你在点一个汉堡&#xff1a; 你说&#xff1a;我要点一个鸡腿汉堡&#xff01; 店员…

深入理解 TCP 协议 | 流量、拥塞及错误控制机制

注&#xff1a;本文为 “TCP 协议” 相关文章合辑。 原文为繁体&#xff0c;注意术语描述差异。 作者在不同的文章中互相引用其不同文章&#xff0c;一并汇总于此。 略作重排&#xff0c;如有内容异常&#xff0c;请看原文。 TCP 三向交握 (Three-way Handshake) 2016-12-21 …

PCL库编译指南

PCL(Point Cloud Library)的编译过程会根据不同操作系统有所差异。以下是详细的编译步骤&#xff1a; Linux/Ubuntu系统编译 1. 安装依赖项 bash sudo apt-get update sudo apt-get install git build-essential linux-libc-dev sudo apt-get install cmake cmake-gui sud…

【Linux】条件变量、基于阻塞队列的生产者消费者模型

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f310; C 语言 进程是资源分配的基本单位&#xff0c;线程是调度的基本单位&#xff0c;线程是在进程内部运行的&#xff08;是进程内部…

32-工艺品商城小程序

技术&#xff1a; 基于 B/S 架构 SpringBootMySQLvueelementuiuniapp 环境&#xff1a; Idea mysql maven jdk1.8 node 可修改为其他类型商城 用户端功能 1.系统首页展示轮播图及工艺品列表 2.分类模块:展示产品的分类类型 3.购物车:进行商品多选结算 或者批量管理操作 4.…

SLAM | 激光SLAM中的退化问题

在激光SLAM中,判断退化环境的核心是通过数学建模分析环境特征对位姿估计的约束能力。除了LOAM中提出的退化因子D外,还存在多种基于表达式和阈值设定的方法。以下是几种典型方法及其实现原理: 1. 协方差矩阵特征值分析 原理:通过分析点云协方差矩阵的特征值分布,判断环境中…

【2025最新版】火鸟门户v8.5系统源码+PC、H5、小程序 +数据化大屏插件

一.介绍 火鸟地方门户系统V8.5源码 系统包含4端&#xff1a; PCH5小程序APP 二.搭建环境 系统环境&#xff1a;CentOS、 运行环境&#xff1a;宝塔 Linux 网站环境&#xff1a;Nginx 1.2.22 MySQL 5.6 PHP-7.4 常见插件&#xff1a;fileinfo &#xff1b; redis 三.测…

PHP腾讯云人脸核身获取NONCE ticket

参考腾讯云官方文档&#xff1a; 人脸核身 获取 NONCE ticket_腾讯云 前提条件&#xff0c;已经成功获取了access token。 获取参考文档&#xff1a; PHP腾讯云人脸核身获取Access Token-CSDN博客 public function getTxFaceNonceTicket($uid) {$access_token file_get_c…

多人3D游戏完整实现方案

以下是一份完整的代码实现方案,涵盖架构设计、核心模块实现和部署流程。我们以 多人3D游戏 为例,结合之前讨论的Nano服务端框架和Unity客户端: 技术栈 模块技术选型服务端Golang + Nano框架 + MongoDB客户端Unity 2022 + C# + Mirror Networking通信协议Protobuf + WebSock…

【Linux我做主】GDB调试工具完全指南

Linux下GDB调试工具完全指南&#xff1a;25个核心命令详解与实战示例 github地址 有梦想的电信狗 前言 GDB&#xff08;GNU Debugger&#xff09;是Linux开发中不可或缺的调试工具&#xff0c;尤其在定位代码逻辑错误和内存问题时表现卓越。本文基于实际开发经验&#xff0…

QT中栅格模式探索

1、Qt中选择了栅格模式&#xff0c;如下图所示&#xff1a; 2、在进行整个大的UI界面布局时&#xff0c;需了解每个控件所需要选择的属性sizePolicy。 sizePolicy包含如下几种选择&#xff1a; 3、举个例子&#xff1a;此时整个UI界面&#xff0c;我采用了栅格模式&#xf…

【计算机网络】3数据链路层①

这篇笔记专门讲数据链路层的功能。 2.功能 数据链路层的主要任务是让帧在一段链路上或一个网络中传输。 2.1.封装成帧(组帧) 解决的问题:①帧定界②帧同步③透明传输 实现组帧的方法通常有以下种。 2.1.1.字符计数法 原理:在每个帧开头,用一个定长计数字段来记录该…

[区块链lab2] 构建具备加密功能的Web服务端

实验目标&#xff1a; 掌握区块链中密码技术的工作原理。在基于Flask框架的服务端中实现哈希算法的加密功能。 实验内容&#xff1a; 构建Flash Web服务器&#xff0c;实现哈希算法、非对称加密算法的加密功能。 实验步骤&#xff1a; 哈希算法的应用&#xff1a;创建hash…

蓝桥杯之前缀和

一维前缀 解题思路 看到“区间之和”问题&#xff0c;直接想到“前缀和” 前缀和的核心公式&#xff1a; sum[i]sum[i−1]a[i] 利用前缀和求区间和 [l,r] 的公式&#xff1a; 区间和sum[r]−sum[l−1] 解题步骤模板 输入数组&#xff1a; 读取数组长度 n 和查询次数 m。 读…

【学习笔记】计算机网络(八)—— 音频/视频服务

第8章 互联网上的音频/视频服务 文章目录 第8章 互联网上的音频/视频服务8.1概述8.2 流式存储音频/视频8.2.1 具有元文件的万维网服务器8.2.2 媒体服务器8.2.3 实时流式协议 RTSP 8.3 交互式音频/视频8.3.1 IP 电话概述8.3.2 IP电话所需要的几种应用协议8.3.3 实时运输协议 RTP…