泛型的二三事

news2025/5/15 16:23:27

泛型(Generics)是Java语言的一个重要特性,它允许在定义类、接口和方法时使用类型参数(Type Parameters),从而实现类型安全的代码重用。泛型在Java 5中被引入,极大地增强了代码的灵活性和安全性。以下是关于泛型的详细介绍,包括其基本概念、使用场景和一些高级特性。


1. 泛型的基本概念

1.1 什么是泛型

泛型允许在定义类、接口或方法时使用类型参数,而不是具体的类型。这样可以在运行时动态指定类型,同时保持类型安全。例如:

class Box<T> { // T 是类型参数
    private T t; // 使用类型参数 T

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }
}

在这个例子中,Box 类使用了类型参数 T,可以在实例化时指定具体的类型,例如:

Box<Integer> intBox = new Box<>();
intBox.set(10);
System.out.println(intBox.get()); // 输出 10
1.2 泛型的好处
  1. 类型安全:编译器会在编译时检查类型是否正确,避免了类型转换错误。

  2. 代码复用:通过泛型可以编写通用的类和方法,减少重复代码。

  3. 减少类型转换:在使用泛型时,不需要显式进行类型转换,代码更加简洁。


2. 泛型的使用场景

2.1 泛型类

泛型类是在类定义时使用类型参数。例如:

class Pair<T, U> {
    private T first;
    private U second;

    public Pair(T first, U second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() {
        return first;
    }

    public U getSecond() {
        return second;
    }
}

使用时:

Pair<String, Integer> pair = new Pair<>("Hello", 123);
System.out.println(pair.getFirst()); // 输出 Hello
System.out.println(pair.getSecond()); // 输出 123
2.2 泛型接口

泛型接口与泛型类类似,可以在接口定义时使用类型参数。例如:

interface Generator<T> {
    T next();
}

实现时:

class RandomNumberGenerator implements Generator<Integer> {
    @Override
    public Integer next() {
        return (int) (Math.random() * 100);
    }
}
2.3 泛型方法

泛型方法是在方法定义时使用类型参数。例如:

public static <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.println(element);
    }
}

调用时:

Integer[] intArray = {1, 2, 3};
String[] strArray = {"Hello", "World"};
printArray(intArray); // 输出 1 2 3
printArray(strArray); // 输出 Hello World

3. 泛型的高级特性

3.1 类型参数的限制(上界)

可以为类型参数指定上界,即类型参数必须是某个类或接口的子类型。例如:

public static <T extends Number> double sum(T[] array) {
    double total = 0;
    for (T element : array) {
        total += element.doubleValue();
    }
    return total;
}

调用时:

Integer[] intArray = {1, 2, 3};
System.out.println(sum(intArray)); // 输出 6.0
3.2 泛型通配符(Wildcards)

泛型通配符用于表示未知类型。主要有以下几种:

  1. 无界通配符(?:表示任意类型

    public static void printList(List<?> list) {
        for (Object element : list) {
            System.out.println(element);
        }
    }
  2. 有界通配符(? extends T:表示类型参数是 T 的子类型

    public static void printNumbers(List<? extends Number> list) {
        for (Number element : list) {
            System.out.println(element);
        }
    }
  3. 有界通配符(? super T:表示类型参数是 T 的父类型

    public static void addNumbers(List<? super Integer> list) {
        list.add(1);
        list.add(2);
    }
3.3 泛型的类型擦除

Java的泛型在运行时会被擦除,即运行时不会保留泛型类型信息。例如:

Box<Integer> intBox = new Box<>();
Box<String> strBox = new Box<>();
System.out.println(intBox.getClass() == strBox.getClass()); // 输出 true

这意味着运行时 intBoxstrBox 的类型是相同的,都是 Box 类。


4. 泛型的常见问题

4.1 泛型方法的类型推断

Java编译器可以自动推断泛型方法的类型参数。例如:

public static <T> T getFirst(T[] array) {
    return array[0];
}

调用时:

Integer first = getFirst(new Integer[]{1, 2, 3}); // 编译器推断 T 为 Integer
4.2 泛型与静态方法

泛型方法不能直接定义在静态方法中,因为静态方法属于类本身,而不是类的实例,而泛型类型参数是与实例相关的。例如:

class Box<T> {
    public static <T> T getFirst(T[] array) { // 错误:静态方法不能使用类的泛型参数
        return array[0];
    }
}
4.3 泛型与数组

不能创建泛型数组,因为数组类型在运行时是固定的,而泛型类型在运行时会被擦除。例如:

T[] array = new T[10]; // 错误:不能创建泛型数组

但可以通过其他方式解决,例如:

T[] array = (T[]) new Object[10];

 5.一个泛型代码分析

先来看一个实例:

这段代码是一个Java程序,用于通过泛型方法找到数组中的最大值。以下是对代码的详细分析和一些需要注意的地方:

5.1代码功能

  1. findmaxvalue 方法

    • 这是一个泛型方法,使用了泛型类型 T,并且要求 T 必须实现 Comparable<T> 接口。这意味着传入的数组元素类型必须是可以比较的(例如 IntegerDoubleString 等)。

    • 方法逻辑:

      • 首先检查数组是否为空或为 null,如果是,则抛出 IllegalArgumentException 异常。

      • 将数组的第一个元素初始化为最大值 max

      • 遍历数组,从第二个元素开始,使用 compareTo 方法比较当前元素和 max 的大小。如果当前元素更大,则更新 max

      • 最后返回最大值。

  2. main 方法

    • 定义了一个 Integer 类型的数组 integers1,并将其设置为 null

    • 调用 Alg.findmaxvalue(integers1) 方法,尝试找到数组中的最大值。

    • 将返回的最大值打印到控制台。

5.2代码运行结果

由于 integers1 被设置为 null,在调用 findmaxvalue 方法时,会触发 findmaxvalue 方法中的异常检查逻辑,抛出 IllegalArgumentException 异常,程序会终止并打印异常信息。

5.3输出结果

运行改进后的代码,输出结果为:

5

如果将 integers1 设置为 null 或空数组,程序会输出:

Error: Array is empty or null

 


6. 总结

泛型是Java语言中一个非常强大的特性,它提供了类型安全、代码复用和减少类型转换的好处。通过泛型类、泛型接口和泛型方法,可以编写更加通用和灵活的代码。同时,理解泛型的高级特性(如类型擦除、通配符等)可以帮助你更好地使用泛型,避免常见问题。

如果你有更多关于泛型的具体问题,欢迎随时提问!

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

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

相关文章

编程思想——FP、OOP、FRP、AOP、IOC、DI、MVC、DTO、DAO

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

【区块链安全 | 第三十九篇】合约审计之delegatecall(一)

文章目录 外部调用函数calldelegatecallcall 与 delegatecall 的区别示例部署后初始状态调用B.testCall()函数调用B.testDelegatecall()函数区别总结漏洞代码代码审计攻击代码攻击原理解析攻击流程修复建议审计思路外部调用函数 在 Solidity 中,常见的两种底层外部函数调用方…

linux多线(进)程编程——(6)共享内存

前言 话说进程君的儿子经过父亲点播后就开始闭关&#xff0c;它想要开发出一种全新的传音神通。他想&#xff0c;如果两个人的大脑生长到了一起&#xff0c;那不是就可以直接知道对方在想什么了吗&#xff0c;这样不是可以避免通过语言传递照成的浪费吗&#xff1f; 下面就是它…

信息安全管理与评估2021年国赛正式卷答案截图以及十套国赛卷

2021年全国职业院校技能大赛高职组 “信息安全管理与评估”赛项 任务书1 赛项时间 共计X小时。 赛项信息 赛项内容 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 第一阶段 平台搭建与安全设备配置防护 任务1 网络平台搭建 任务2 网络安全设备配置与防护 第二…

高并发秒杀系统设计:关键技术解析与典型陷阱规避

电商、在线票务等众多互联网业务场景中&#xff0c;高并发秒杀活动屡见不鲜。这类活动往往在短时间内会涌入海量的用户请求&#xff0c;对系统架构的性能、稳定性和可用性提出了极高的挑战。曾经&#xff0c;高并发秒杀架构设计让许多开发者望而生畏&#xff0c;然而&#xff0…

微信小程序实战案例 - 餐馆点餐系统 阶段 2 – 购物车

阶段 2 – 购物车&#xff08;超详细版&#xff09; 目标 把“加入购物车”做成 全局状态&#xff0c;任何页面都能读写在本地 持久化&#xff08;关闭小程序后购物车仍在&#xff09;新建 购物车页&#xff1a;数量增减、总价实时计算、去结算入口打 Git Tag v2.0‑cart 1. …

sql 向Java的映射

优化建议&#xff0c;可以在SQL中控制它的类型 在 MyBatis 中&#xff0c;如果返回值类型设置为 java.util.Map&#xff0c;默认情况下可以返回 多行多列的数据

Visual Studio未能加载相应的Package包弹窗报错

环境介绍&#xff1a; visulal studio 2019 问题描述&#xff1a; 起因&#xff1a;安装vs扩展插件后&#xff0c;重新打开Visual Studio&#xff0c;报了一些列如下的弹窗错误&#xff0c;即使选择不继续显示该错误&#xff0c;再次打开后任然报错&#xff1b; 解决思路&am…

【HD-RK3576-PI】Docker搭建与使用

硬件&#xff1a;HD-RK3576-PI 软件&#xff1a;Linux6.1Ubuntu22.04 1.Docker 简介 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言开发&#xff0c;遵循 Apache 2.0 协议。它可以让开发者将应用程序及其依赖项打包到一个轻量级、可移植的容器中&#xff0c;并在任…

【websocket】使用案例( ​JSR 356 标准)

目录 一、JSR 356方式&#xff1a;简单示例 1、引入依赖 2、注册端点扫描器 3、编写通过注解处理生命周期和消息 4、细节解读 5、总结 二、聊天室案例 方案流程 1、引入依赖 2、注册端点扫描器 3、编写一个配置类&#xff0c;读取httpsession 4、编写通过注解处理生…

IS-IS中特殊字段——OL过载

文章目录 OL 过载位 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Datacom专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年04月13日20点12分 OL 过载位 路由过载 使用 IS-IS 的过载标记来标识过载状态 对设备设置过载标记后&#xff…

【时频谱分析】快速谱峭度

算法配置页面&#xff0c;也可以一键导出结果数据 报表自定义绘制 获取和下载【PHM学习软件PHM源码】的方式 获取方式&#xff1a;Docshttps://jcn362s9p4t8.feishu.cn/wiki/A0NXwPxY3ie1cGkOy08cru6vnvc

Spring Boot 支持的内嵌服务器(Tomcat、Jetty、Undertow、Netty(用于 WebFlux 响应式应用))详解

Spring Boot 支持的内嵌服务器详解 1. 支持的内嵌服务器 Spring Boot 默认支持以下内嵌服务器&#xff1a; Tomcat&#xff08;默认&#xff09;JettyUndertowNetty&#xff08;用于 WebFlux 响应式应用&#xff09; 2. 各服务器使用示例 (1) Tomcat&#xff08;默认&#xf…

微软Exchange管理中心全球范围宕机

微软已确认Exchange管理中心&#xff08;Exchange Admin Center&#xff0c;EAC&#xff09;发生全球性服务中断&#xff0c;导致管理员无法访问关键管理工具。该故障被标记为关键服务事件&#xff08;编号EX1051697&#xff09;&#xff0c;对依赖Exchange Online的企业造成广…

基于Qt的串口通信工具

程序介绍 该程序是一个基于Qt的串口通信工具&#xff0c;专用于ESP8266 WiFi模块的AT指令配置与调试。主要功能包括&#xff1a; 1. 核心功能 串口通信&#xff1a;支持串口开关、参数配置&#xff08;波特率、数据位、停止位、校验位&#xff09;及数据收发。 AT指令操作&a…

html简易实现推箱子小游戏原理(易上手)

实现效果 使用方向键移动&#xff0c;将橙色箱子推到绿色目标区域&#xff08;黑色块为墙&#xff0c;白色块为可通过区域&#xff0c;蓝球为小人&#xff09; 实现过程 <!DOCTYPE html> <html> <head><title>推箱子小游戏</title><style&g…

字符串与栈和队列-算法小结

字符串 双指针 反转字符串(双指针) 力扣题目链接 void reverseString(vector<char>& s) {for (int i 0, j s.size() - 1; i < s.size()/2; i, j--) {swap(s[i],s[j]);} }反转字符串II 力扣题目链接 遍历字符串的过程中&#xff0c;只要让 i (2 * k)&#…

类似东郊到家的上门按摩预约服务系统小程序APP源码全开源

&#x1f525; 为什么上门按摩正在席卷全国&#xff1f; 万亿蓝海市场爆发 2024年中国按摩市场规模突破8000亿&#xff0c;上门服务增速达65% 90后成消费主力&#xff0c;**72%**白领每月至少使用1次上门按摩&#xff08;数据来源&#xff1a;艾媒咨询&#xff09; 传统痛点…

Python | 在Pandas中按照中值对箱形图排序

箱形图是可视化数据分布的强大工具&#xff0c;因为它们提供了对数据集内的散布、四分位数和离群值的洞察。然而&#xff0c;当处理多个组或类别时&#xff0c;通过特定的测量&#xff08;如中位数&#xff09;对箱形图进行排序可以提高清晰度并有助于揭示模式。在本文中&#…

游戏引擎学习第215天

总结并为今天做铺垫 今天的工作内容是解决调试系统中的一个小问题。昨天我们已经完成了大部分的调试系统工作&#xff0c;但还有一个小部分没有完全处理&#xff0c;那就是关于如何层次化组织数据的问题。我们遇到的一个问题是&#xff0c;演示代码中仍有一个尚未解决的部分&a…