Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【Java 基础篇】Java 泛型:类型安全的编程指南

【Java 基础篇】Java 泛型:类型安全的编程指南

作者头像
繁依Fanyi
发布于 2023-10-12 08:13:11
发布于 2023-10-12 08:13:11
46400
代码可运行
举报
运行总次数:0
代码可运行

Java 编程中,泛型是一项强大的特性,它允许您编写更通用、更安全和更灵活的代码。无论您是初学者还是有经验的 Java 开发人员,了解和掌握泛型都是非常重要的。本篇博客将从基础概念一直深入到高级应用,详细介绍 Java 泛型。

什么是泛型?

泛型是 Java 编程语言的一项特性,用于实现通用性更强的类、接口和方法。它允许您编写一次代码,然后可以用于多种数据类型,而不需要为每种数据类型都编写不同的代码。泛型的核心思想是参数化类型,即在定义类、接口或方法时,可以将类型作为参数传递。

泛型的主要优点包括:

  • 类型安全性:泛型可以在编译时捕获类型错误,而不是在运行时发生异常。这可以帮助您在编写代码时检测和修复错误,提高代码的可靠性。
  • 代码复用:泛型允许您编写通用的代码,可以适用于不同类型的数据。这样,您可以避免重复编写类似的代码。
  • 更清晰的代码:使用泛型可以使代码更易于理解和维护,因为它提供了更多的类型信息。

泛型的基本用法

泛型类

首先,让我们从泛型类开始,了解如何定义和使用泛型类。泛型类可以接受一个或多个类型参数,并在类的定义中使用这些参数。例如,下面是一个简单的泛型类 Box,用于存储任意类型的对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Box<T> {
    private T data;

    public Box(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }
}

在上面的示例中,Box 类接受一个类型参数 T,然后使用 T 来定义数据字段和方法。这使得 Box 类可以存储不同类型的数据。

泛型方法

除了泛型类,Java 还支持泛型方法。泛型方法是在方法中使用泛型类型参数的方法。例如,下面是一个泛型方法 printArray,用于打印数组中的元素:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public <T> void printArray(T[] array) {
    for (T item : array) {
        System.out.print(item + " ");
    }
    System.out.println();
}

在上面的示例中,<T> 表示 printArray 方法接受一个类型参数 T,然后可以在方法中使用 T 类型。

使用泛型类和方法

使用泛型类和方法非常简单。以下是一些示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
    // 使用泛型类
    Box<Integer> intBox = new Box<>(42);
    int value = intBox.getData(); // 获取存储的整数

    // 使用泛型方法
    String[] strings = {"Hello", "World"};
    printArray(strings); // 打印字符串数组

    Integer[] integers = {1, 2, 3};
    printArray(integers); // 打印整数数组
}

在上面的示例中,我们创建了一个 Box 对象来存储整数,并使用 printArray 方法分别打印了字符串数组和整数数组。

泛型的通配符

通配符是一种用于处理未知类型的泛型的方式。Java 中有两种通配符:?? extends T。它们允许您编写能够处理不同类型的泛型代码。

通配符 ?

通配符 ? 表示未知类型,可以用于表示任意类型的泛型。通常情况下,通配符 ? 用于方法参数中,以接受各种类型的数据。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void printList(List<?> list) {
    for (Object item : list) {
        System.out.print(item + " ");
    }
    System.out.println();
}

上面的示例中,printList 方法接受一个未知类型的列表,并打印列表中的元素。这使得方法可以接受不同类型的列表。

通配符 ? extends T

通配符 ? extends T 表示类型限定,它表示通配符可以接受 T 类型或其子类型。这通常用于方法参数中,以确保只能接受指定类型及其子类型的数据。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public double sumOfList(List<? extends Number> list) {
    double sum = 0.0;
    for (Number number : list) {
        sum += number.doubleValue();
    }
    return sum;
}

在上面的示例中,sumOfList 方法接受一个限定为 Number 或其子类型的列表,并计算列表中所有元素的总和。

泛型的限制和约束

在使用泛型时,有一些限制和约束需要注意:

类型擦除

Java 中的泛型是通过类型擦除来实现的。这意味着在编译时,泛型类型信息会被擦除,代码中只剩下原始类型。这可以带来一些限制,例如不能创建泛型数组和无法获得泛型的实际类型参数。

泛型数组

不能直接创建带有泛型类型参数的数组。例如,以下代码是不合法的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List<String>[] arrayOfLists = new List<String>[10]; // 不合法

但是,可以使用通配符 ? 创建泛型数组:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List<?>[] arrayOfLists = new List<?>[10]; // 合法
泛型和继承

泛型类不能继承自 Throwable 类,这意味着不能创建泛型异常类。

泛型和基本数据类型

泛型不能用于基本数据类型(如 intchardouble 等),只能用于引用数据类型。如果需要操作基本数据类型,可以使用对应的包装类(如 IntegerCharacterDouble 等)。

泛型的高级应用

除了基本用法和限制,泛型还具有一些高级应用,如通配符的上限和下限、泛型方法的类型推断、泛型的反射和通配符捕获等。这些高级主题超出了本篇博客的范围,但可以在进一步学习 Java 泛型时深入探讨。

泛型使用注意事项

当使用泛型时,有一些重要的注意事项和最佳实践,以确保您的代码正确、安全且易于维护。以下是一些泛型的使用注意事项:

类型擦除: 泛型信息在编译时会被擦除,这意味着在运行时无法获得泛型的实际类型参数。因此,不能在运行时检查泛型类型。例如,以下代码将引发编译错误:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 编译错误:无法检查泛型类型
if (list instanceof List<String>) {
    // ...
}

要注意,虽然编译器会发出警告,但在运行时不会引发异常。

泛型数组: 直接创建带有泛型类型参数的数组是不合法的。但可以使用通配符 ? 创建泛型数组,如 List<?>[]。如果需要数组结构,通常建议使用集合(如 ListArrayList)而不是数组。

通配符捕获: 当使用通配符(例如 <?><? extends T>)时,可以捕获通配符的实际类型参数,但在方法内部无法修改通配符的类型。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void process(List<?> list) {
    // 编译错误:无法添加元素到通配符列表
    list.add("Hello");
}

在这种情况下,可以使用带有类型参数的辅助方法来处理通配符列表。

避免原始类型: 尽量避免使用原始类型,而是使用泛型类。原始类型是泛型的历史遗留物,不安全且不推荐使用。

泛型方法类型推断: 在调用泛型方法时,可以省略类型参数,编译器会根据参数的类型自动推断出类型参数。这样可以使代码更简洁,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");

// 类型推断:不需要指定类型参数
String first = getFirstElement(names);

泛型通配符: 使用通配符可以实现灵活的泛型参数传递,但需要注意通配符的上限和下限。通配符 <? extends T> 表示类型上限,通配符 <? super T> 表示类型下限。选择合适的通配符可以提高代码的可用性和安全性。

类型转换警告: 在使用泛型时,可能会遇到类型转换警告,例如使用原始类型或未检查的转换。在遇到这些警告时,应谨慎处理,并尽量避免类型不安全的转换。

泛型和继承: 注意泛型类不能继承自 Throwable,因此不能创建泛型异常类。同时,泛型类的类型参数不会继承,例如 List<Child> 不是 List<Parent> 的子类型。

泛型和基本数据类型: 泛型不能用于基本数据类型(如 intchardouble 等),只能用于引用数据类型。如果需要操作基本数据类型,可以使用对应的包装类(如 IntegerCharacterDouble 等)。

通配符和可读性: 虽然通配符可以提高代码的灵活性,但过度使用通配符可能会降低代码的可读性。在选择是否使用通配符时,需要权衡代码的清晰度和灵活性。

总之,泛型是 Java 中强大的特性,可以提高代码的安全性和可维护性。但要谨慎使用,遵循最佳实践,以避免潜在的问题。随着更多的实践和学习,您将能够更好地利用泛型来编写高质量的 Java 代码。

结语

本篇博客介绍了 Java 泛型的基本概念、用法以及一些限制。泛型是 Java 中强大且重要的特性,它可以帮助您编写更安全、更通用的代码。通过深入学习和实践,您可以更好地理解和应用泛型,提高 Java 编程的效率和质量。希望本博客能帮助您入门和精通 Java 泛型。如果您有任何问题或需要进一步的帮助,请随时留下评论。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C语言加油站】qsort函数的模拟实现
在数组篇章中,咱们有介绍过一种排序的方式——冒泡排序。不知道大家还有没有印象,如果没印象也没关系,等会我们会再简单介绍一下,今天我们要介绍的主角是C语言提供的一个进行排序的库函数——qsort。下面我们就开始今天的内容吧!!!
蒙奇D索隆
2023/12/19
1730
【C语言加油站】qsort函数的模拟实现
【c语言】qsort函数及泛型冒泡排序的模拟实现
在了解qsort函数之前,我们先来学习一个概念:回调函数。那么回调函数是什么呢?
ephemerals__
2024/10/24
1400
【c语言】qsort函数及泛型冒泡排序的模拟实现
指针(6)---qsort函数
我们都知道数组的起始位置其实就是数组名,所以这里的含义其实也就是数组名的意思。而且由于可能要排序任意类型的数据,故设计成void*
Skrrapper
2024/06/18
1070
手把手教你使用qsort函数
qsort的作用是对不同数据类型的数组的内容进行排序,排序的升序降序可以由你所提供的函数参数所改变。
大海里的番茄
2024/01/19
1910
手把手教你使用qsort函数
【C语言】手把手带你拿捏指针(4)(含qsort函数详解)
什么是回调函数?    回调函数就是⼀个通过函数指针调用的函数。    如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发⽣时由另外的一方调用的,用于对该事件或条件进行响应    可能这么说着有些抽象,我们还是举一个例子,比如上一篇文章我们讲到的计算器,我们当时为了解决代码冗余,使用了转移表,也就是函数指针数组,那么是否还有其它方法呢?比如我坚持使用Switch语句,而不使用if语句    这个内容就涉及到我们的回调函数,回调函数简单地说就是将函数指针传给另一个函数,通过这个函数来使用传过来的函数    我们可以将之前冗余的部分包装成函数,最大的冗余就是那个Switch语句,我们来看看冗余部分:
TANGLONG
2024/10/15
1170
【C语言】手把手带你拿捏指针(4)(含qsort函数详解)
【指针进阶三】实现C语言快排函数qsort&回调函数
因为cmp比较函数需要使用者自行设计,所以对于不同的使用者在qsort函数里传给cmp函数的参数类型可能是任何类型的指针,所以在cmp比较函数内得用void*类型的指针来接收,使用时只需将void* 类型的指针做出相应的强转即可。
MicroFrank
2023/01/16
5090
C语言-qsort函数的使用与实现
认识一个新的函数,我们就应该知道它的参数与返回,我们可以通过MSDN去查找相关信息
HABuo
2024/11/19
1210
C语言-qsort函数的使用与实现
剖析C语言回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用,用于对该事件或条件进行响应。
用户11316056
2024/10/16
2040
剖析C语言回调函数
C语言学习系列-->【关于qsort函数的详解以及它的模拟实现】
对数组的元素进行排序 对数组中由 指向的元素进行排序,每个元素字节长,使用该函数确定顺序。 此函数使用的排序算法通过调用指定的函数来比较元素对,并将指向它们的指针作为参数。
南桥
2024/01/26
1560
C语言学习系列-->【关于qsort函数的详解以及它的模拟实现】
c语言qsort函数的模拟实现
回调函数就是⼀个通过函数指针调用的函数。 如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 这样讲也许会有点抽象,等下面讲到实际案例时再具体介绍:>
用户11029269
2024/03/19
1700
c语言qsort函数的模拟实现
【C语言篇】深入理解指针4(模拟实现qsort函数)
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。
半截诗
2024/10/09
1020
【C语言篇】深入理解指针4(模拟实现qsort函数)
[C语言日寄]以指针进阶:空类型指针与qsort函数
在C语言的学习中,指针始终是一个核心且难以绕开的话题。它既强大又容易出错,但一旦掌握,就能极大地提升代码的灵活性和效率。今天,我们将通过一个具体的题目,深入探讨空类型指针(void*)和C标准库中的qsort函数,帮助大家更好地理解和应用指针的高级特性。
siy2333
2025/02/25
1070
[C语言日寄] qsort函数的练习
在C语言的世界里,qsort 函数是一个非常强大且灵活的工具,它允许我们对任意类型的数组进行快速排序。这种特性使得 qsort 在处理复杂数据排序时变得非常方便。今天,我们就通过一个简单的程序来深入探讨 qsort 的使用,以及它在C语言中的重要性。
siy2333
2025/03/16
660
【C语言】qsort函数介绍
讲这个东西之前我们来认识一下回调函数,回调函数就是一个通过函数指针调用的函数。 如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数 时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
用户11290673
2024/09/25
1050
【C语言】qsort函数介绍
C语言---深入指针(4)
对于qsort函数来说,我们只需要额外构建一个比较函数就能利用qsort进行快速排列
Undoom
2024/09/23
1100
用qsort函数来模拟实现全类型的冒泡排序
缺点:效率不高 (如果一个数组有n个数,那么排序完成后需要比较n*(n-1)/2次) 并且一般适用于整形 如果是结构体类型,浮点型类型或者其他类型,就会很麻烦
用户11369558
2024/11/20
640
用qsort函数来模拟实现全类型的冒泡排序
qsort函数的使用和模拟实现排序
自我介绍:一个脑子不好的大一学生,c语言接触还没到半年,若涉及到效率等问题,各位都可以在评论区提出见解,谢谢啦。
用户11039529
2024/03/25
1890
qsort函数的使用和模拟实现排序
冒泡排序的快速排序——qsort函数的模拟实现
上一期我们留下了一个题目: 判断一个字符串是否是另一个字符串左旋后的字符: 其实我们只要将原字符串用memcpy加到原字符串的后面构成一个新的字符串,只要你给出的字符串在这个新的字符串里面(用strstr函数),那么他就是这个字符串左旋后的字符串 例如:BCDA如果在下面的这个字符串中,所以是左旋后的字符串
ahao
2024/03/19
1090
冒泡排序的快速排序——qsort函数的模拟实现
qsort函数的应用以及模拟实现
strcmp函数用于比较字符串的,它的比较方式是比较字符的ASCII码值,并不是长度,后续在库函数模拟篇会讲到.
初阶牛
2023/03/08
6460
qsort函数的应用以及模拟实现
C语言-qosrt函数—秩序大师
在cplusplus(C语言函数查询网站)上,我们可以看到qsort函数的函数原型
LonlyMay
2024/10/21
930
C语言-qosrt函数—秩序大师
相关推荐
【C语言加油站】qsort函数的模拟实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验