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

【Java基础-46.3】Java泛型通配符详解:解锁类型安全的灵活编程

在Java中,泛型(Generics)是提高代码复用性和类型安全的重要特性。然而,泛型的严格类型约束有时会限制代码的灵活性。为了解决这个问题,Java引入了泛型通配符(Wildcards),它允许我们编写更通用的代码,同时保持类型安全。本文将深入探讨泛型通配符的概念、用法以及实际应用场景。


1. 泛型通配符是什么?

泛型通配符用?表示,它代表一种未知的类型。通配符通常用于以下场景:

  • 处理泛型集合时,允许接受多种类型的参数。
  • 在方法参数或返回值中,提供更灵活的类型支持。

通配符可以分为以下三种:

  1. 无界通配符(Unbounded Wildcard)<?>
  2. 上界通配符(Upper Bounded Wildcard)<? extends T>
  3. 下界通配符(Lower Bounded Wildcard)<? super T>

2. 无界通配符(<?>)

无界通配符表示任意类型。它通常用于以下场景:

  • 当你只关心泛型集合的操作(如遍历),而不关心具体类型时。

2.1 示例:遍历任意类型的集合

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

public static void main(String[] args) {
    List<Integer> intList = Arrays.asList(1, 2, 3);
    List<String> strList = Arrays.asList("A", "B", "C");

    printList(intList); // 输出:1 2 3
    printList(strList); // 输出:A B C
}

在这个例子中,printList方法可以接受任何类型的List,因为<?>表示未知类型。


3. 上界通配符(<? extends T>)

上界通配符表示“某种类型或其子类型”。它通常用于以下场景:

  • 当你需要从泛型集合中读取数据,但不允许写入数据时。

3.1 示例:处理数字类型的集合

public static double sumOfList(List<? extends Number> list) {
    double sum = 0.0;
    for (Number num : list) {
        sum += num.doubleValue();
    }
    return sum;
}

public static void main(String[] args) {
    List<Integer> intList = Arrays.asList(1, 2, 3);
    List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);

    System.out.println(sumOfList(intList));    // 输出:6.0
    System.out.println(sumOfList(doubleList)); // 输出:6.6
}

在这个例子中,sumOfList方法可以接受Number或其子类型(如IntegerDouble)的集合。

注意事项:

  • 使用<? extends T>时,只能从集合中读取数据,不能写入数据(除了null),因为具体类型未知。

4. 下界通配符(<? super T>)

下界通配符表示“某种类型或其父类型”。它通常用于以下场景:

  • 当你需要向泛型集合中写入数据,但不关心读取数据的类型时。

4.1 示例:向集合中添加元素

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 5; i++) {
        list.add(i);
    }
}

public static void main(String[] args) {
    List<Number> numList = new ArrayList<>();
    List<Object> objList = new ArrayList<>();

    addNumbers(numList); // 添加Integer到Number集合
    addNumbers(objList); // 添加Integer到Object集合

    System.out.println(numList); // 输出:[1, 2, 3, 4, 5]
    System.out.println(objList); // 输出:[1, 2, 3, 4, 5]
}

在这个例子中,addNumbers方法可以向Integer或其父类型(如NumberObject)的集合中添加元素。

注意事项:

  • 使用<? super T>时,可以向集合中写入数据,但读取数据时只能以Object类型接收。

5. PECS原则

为了更清晰地理解上界和下界通配符的使用场景,我们可以参考PECS原则

  • Producer Extends:如果泛型集合是生产者(提供数据),使用<? extends T>
  • Consumer Super:如果泛型集合是消费者(接收数据),使用<? super T>

5.1 示例:结合PECS原则

public static <T> void copy(List<? extends T> src, List<? super T> dest) {
    for (T item : src) {
        dest.add(item);
    }
}

public static void main(String[] args) {
    List<Integer> src = Arrays.asList(1, 2, 3);
    List<Number> dest = new ArrayList<>();

    copy(src, dest); // 将Integer集合复制到Number集合
    System.out.println(dest); // 输出:[1, 2, 3]
}

在这个例子中,src是生产者(提供数据),因此使用<? extends T>dest是消费者(接收数据),因此使用<? super T>


6. 实际应用场景

6.1 集合工具类

Java标准库中的Collections工具类大量使用了泛型通配符。例如:

public static <T> void sort(List<T> list, Comparator<? super T> c) {
    // 排序逻辑
}

这里使用<? super T>是为了允许传入T或其父类型的比较器。

6.2 泛型方法

在编写泛型方法时,通配符可以提高方法的灵活性。例如:

public static <T> void printFirst(List<? extends T> list) {
    if (!list.isEmpty()) {
        System.out.println(list.get(0));
    }
}

7. 总结

泛型通配符是Java泛型中一个强大的工具,它通过<?><? extends T><? super T>提供了灵活的类型支持。理解并掌握通配符的用法,可以帮助你编写更通用、更安全的代码。记住PECS原则,合理选择上界和下界通配符,可以让你的代码更加优雅和高效。


http://www.kler.cn/a/556320.html

相关文章:

  • JavaScript如何创建一个对象?对象字面量和构造函数创建对象有什么区别?
  • 【第三节】C++设计模式(创建型模式)-单例模式
  • 通过监督微调提升多语言大语言模型性能
  • 模电知识点总结(5)
  • docker 和 Quay.io的关系
  • 使用 ^= 对每个字节进行异或操作完成校验和
  • Elasticsearch实战应用:从“搜索小白”到“数据侦探”的进阶之路
  • 5分钟下载excel模板
  • 【deepseek】本地部署+RAG知识库挂载+对话测试
  • 【Film】论文:2024 视频生成可以取代摄影师吗?生成视频的电影语言研究
  • GB28181协议详解
  • RabbitMQ报错:Shutdown Signal channel error; protocol method
  • 浅谈Word2vec算法模型
  • SpringBoot+Vue+Mysql苍穹外卖
  • 设备树及gpio子系统及ioctl控制及字符设备驱动及内核模块编程事项仨LED灯说点就点说灭就灭
  • VMWare安装Debian操作系统
  • CSS 解决 Flex 布局中 justify-content: space-between; 导致最后一排项目分散对齐的问题
  • 数据结构——二叉树经典习题讲解
  • MATLAB学习之旅:从入门到基础实践
  • 【.NET全栈】.NET包含的所有技术