Java中List<? extends T>与List<? super T>的区别

2024-05-11 04:28
文章标签 java 区别 list super extends

本文主要是介绍Java中List<? extends T>与List<? super T>的区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 概述
  • List<? extends T>
  • List<? super T>
  • <T extends Comparable<? super T>>
  • 示例

概述

在Java中,List<? extends T>List<? super T>是用于表示具有泛型参数的列表的类型声明。它们之间的区别在于它们的作用和限制。

  1. List<? extends T>:这表示一个包含T或T的子类的列表。使用extends关键字限定了类型的上界。这种声明方式使得列表只能读取元素,而不能添加新的元素。原因是编译器无法确定要添加的元素类型是否与列表中的类型兼容。例如:
List<? extends Number> numbers = new ArrayList<>();
Number number = numbers.get(0); // 可以读取元素
numbers.add(10); // 编译错误,无法确定要添加的元素类型
  1. List<? super T>:这表示一个包含T或T的超类的列表。使用super关键字限定了类型的下界。这种声明方式使得列表可以添加T类型的元素,但读取元素时只能作为Object类型处理。例如:
List<? super Integer> integers = new ArrayList<>();
integers.add(10); // 可以添加Integer及其子类的元素
Object obj = integers.get(0); // 只能读取为Object类型
Integer integer = integers.get(0); // 编译错误,无法确定列表中的元素类型

总结:

  • List<? extends T>适用于读取元素,无法添加新元素。
  • List<? super T>适用于添加T类型的元素,读取时需要将元素视为Object类型。

这些通配符类型声明允许我们在类型安全的前提下操作具有不同泛型参数的列表。

List<? extends T>

当我们使用List<? extends T>时,无法添加新元素的原因涉及到泛型的协变性和类型安全性的考虑。

  1. 泛型协变性(Generics Covariance):

    • 泛型协变性是指对于类型AB,如果BA的子类型,那么List<B>List<A>的子类型。
    • 在Java中,数组是具有协变性的,即B[]A[]的子类型,但泛型是不具备协变性的。这是因为泛型在编译时会进行类型擦除,无法在运行时获得泛型参数的实际类型信息。
  2. 通配符限定的类型:

    • List<? extends T>表示一个未知的类型,该类型是TT的子类型。
    • 当我们声明一个类型为List<? extends T>的变量时,编译器无法确定具体的子类型是什么。它只知道该列表中的元素是TT的子类型,但无法具体指定是哪个子类型。
    • 这种情况下,编译器为了保持类型安全性,禁止我们向列表中添加新元素。因为无法确定要添加的元素与列表中元素的实际类型是否兼容。
  3. 类型不一致的问题:

    • 假设我们可以向List<? extends T>添加新元素,那么我们可能会遇到类型不一致的问题。
    • 如果编译器允许我们添加一个类型为U的元素到List<? extends T>中,而实际列表的元素类型是T的子类型V,那么在读取元素时,我们可能会将一个V类型的元素错误地赋值给类型为U的变量,导致类型错误。
    • 为了避免这种类型不一致的情况,编译器禁止在使用List<? extends T>时添加新元素,以保持类型安全性。

总结:

  • List<? extends T>表示一个未知的TT的子类型的列表。
  • 无法向List<? extends T>添加新元素,因为编译器无法确定列表的具体子类型,为了维持类型安全性,禁止添加操作。
  • 这样做是为了避免类型不一致的问题,即将错误类型的元素放入列表中,导致在读取元素时发生类型错误。
  • 泛型在编译时进行类型擦除,无法在运行时获得泛型参数的具体类型信息,这也是泛型不具备协变性的原因之一。

List<? super T>

当使用 List<? super T> 时,只能添加类型为 TT 的子类的元素,这涉及到泛型的逆变性和类型安全性的考虑。

  1. 泛型逆变性(Generics Contravariance):

    • 泛型逆变性是指对于类型 AB,如果 AB 的子类型,那么 List<B>List<A> 的子类型。
    • 在 Java 中,数组是具有逆变性的,即 B[]A[] 的子类型,但泛型是不具备逆变性的。这是因为泛型在编译时会进行类型擦除,无法在运行时获得泛型参数的实际类型信息。
  2. 通配符限定的类型:

    • List<? super T> 表示一个未知的类型,该类型是 TT 的超类。
    • 当我们声明一个类型为 List<? super T> 的变量时,编译器无法确定具体的超类类型是什么。它只知道该列表中的元素是 TT 的超类,但无法具体指定是哪个超类类型。
    • 这种情况下,编译器为了保持类型安全性,限制我们只能添加类型为 TT 的子类的元素。因为只有这样的元素才能确保与列表的类型约束兼容。
  3. 类型不一致的问题:

    • 假设我们可以向 List<? super T> 添加除 TT 的子类之外的元素,那么我们可能会遇到类型不一致的问题。
    • 如果编译器允许我们添加一个不是 TT 的子类的元素到 List<? super T> 中,而实际列表的超类类型是 T 的父类 U,那么在读取元素时,我们可能会将一个 U 类型的元素错误地赋值给类型为 T 的变量,导致类型错误。
    • 为了避免这种类型不一致的情况,编译器限制在使用 List<? super T> 时只能添加类型为 TT 的子类的元素,以保持类型安全性。

总结:

  • List<? super T> 表示一个未知的 TT 的超类的列表。
  • 只能向 List<? super T> 添加类型为 TT 的子类的元素,是为了保证类型安全性,避免类型不一致的问题。
  • 这样做提供了灵活性,允许引用超类类型为 TT 的超类的列表,并安全地添加符合约束的元素。
  • 泛型在编译时进行类型擦除,无法在运行时获得泛型参数的具体类型信息,这也是泛型不具备逆变性的原因之一。

<T extends Comparable<? super T>>

<T extends Comparable<? super T>> 是一个泛型约束(generic constraint),它用于限制泛型类型参数 T。
表示T必须是实现了Comparable接口,或者T的父类实现了Comparable接口

示例

  • 泛型类
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class Container<T> {private List<? super T> items = new ArrayList<>();public void addItem(T item) {items.add(item);}public void addItems(List<? extends T> itemList) {items.addAll(itemList);}public List<? super T> getItems() {return items;}
}Container<Animal> animalContainer = new Container<>();
animalContainer.addItem(new Dog());
animalContainer.addItem(new Cat());List<Dog> dogList = new ArrayList<>();
dogList.add(new Dog());
dogList.add(new Dog());animalContainer.addItems(dogList);List<? super Animal> items = animalContainer.getItems();

在这个例子中,Container 类是一个泛型类,使用 List<? super T> 作为成员变量的类型。我们可以向 Container 对象中添加 T 类型或 T 的子类的元素,并且可以通过 addItems 方法添加 List<? extends T> 类型的列表。通过 getItems 方法获取到的列表类型是 List<? super T>。

这些示例展示了 <? super T> 的应用场景,它可以用于方法参数、泛型类中的成员变量等,提供了更大的灵活性和多态性,允许处理不同类型的列表并进行元素操作。

  • 泛型方法
public static <T> void addElements(List<? super T> list, T[] elements) {for (T element : elements) {list.add(element);}
}List<Object> objectList = new ArrayList<>();
String[] strings = {"Hello", "World"};
addElements(objectList, strings);  // 向 Object 类型的列表添加 String 类型的元素

在这个例子中,addElements 是一个泛型方法,接受一个 List<? super T> 类型的列表和一个 T 类型的数组。我们可以将不同类型的数组元素添加到列表中,只要它们是 T 类型或 T 的子类。

  • 泛型接口
interface Eater<T> {void eat(List<? super T> foodList);
}class AnimalEater<T> implements Eater<T> {public void eat(List<? super T> foodList) {for (Object food : foodList) {// 进行吃食物的操作}}
}List<Object> foodList = new ArrayList<>();
foodList.add("Meat");
foodList.add("Fish");Eater<String> eater = new AnimalEater<>();
eater.eat(foodList);  // AnimalEater 实例可以接受 List<Object> 类型的食物列表

在这个例子中,Eater 是一个泛型接口,定义了一个 eat 方法,接受一个 List<? super T> 参数。AnimalEater 类实现了 Eater 接口,并针对不同类型的食物列表进行吃食物的操作。通过使用 <? super T>,我们可以在实现类中接受不同类型的食物列表,只要它们是 T 类型或 T 的超类。

这些示例展示了 <? super T> 在泛型方法和接口实现中的应用,它使得代码更加灵活,能够处理不同类型的数据并进行相应的操作。

这篇关于Java中List<? extends T>与List<? super T>的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978500

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

破茧 JDBC:MyBatis 在 Spring Boot 中的轻量实践指南

《破茧JDBC:MyBatis在SpringBoot中的轻量实践指南》MyBatis是持久层框架,简化JDBC开发,通过接口+XML/注解实现数据访问,动态代理生成实现类,支持增删改查及参数... 目录一、什么是 MyBATis二、 MyBatis 入门2.1、创建项目2.2、配置数据库连接字符串2.3、入

Springboot项目启动失败提示找不到dao类的解决

《Springboot项目启动失败提示找不到dao类的解决》SpringBoot启动失败,因ProductServiceImpl未正确注入ProductDao,原因:Dao未注册为Bean,解决:在启... 目录错误描述原因解决方法总结***************************APPLICA编

深度解析Spring Security 中的 SecurityFilterChain核心功能

《深度解析SpringSecurity中的SecurityFilterChain核心功能》SecurityFilterChain通过组件化配置、类型安全路径匹配、多链协同三大特性,重构了Spri... 目录Spring Security 中的SecurityFilterChain深度解析一、Security

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav