java语言是符合里氏替换原则的,即任何基类可以出现的地方,子类一定可以出现。
为了获取更大限度的灵活性,要在表示生产者或者消费者的输入参数上使用通配符类型,PS:通配符用于声明形参,不能用于类和创建对象上。
声明上下界
- list<? extends Number>:定义下界,说明List中可能包含的元素类型是Number及其子类
- List<? super Number>:定义上界,则说明List中包含的是Number及其父类
PECS原则
PECS指“Producer Extends,Consumer Super”。换句话说,如果参数化类型表示一个生产者,就使用<? extends T>;如果它表示一个消费者,就使用<? super T>。
生产者
假如从列表或者迭代器中get T类型的元素,需要声明成<? extends T>,比如List< ? extends Integer>,此时可以保证从参数get到的元素至少是T。
消费者
假如如把T类型的元素 put 到参数(列表)中,需要把这个参数声明成< ? super T>,比如List<? super Integer>,此时可以保证put T类型到参数中。
既是生产者又是消费者
不要使用泛型
例子
下面是一个简单的Stack的API接口:
public class Stack<E> { public Stack(); public void push(E e); public E pop(); public boolean isEmpty(); }
假设想增加一个方法,按顺序将一系列元素全部放入Stack中,你可能想到的实现方式如下:
//参数src生产实例(生产者,输出对象),保证src里面的对象是stack对象的子类 public void pushAll(Iterable<? extends E> src) { for (E e : src) push(e); }
与之对应的是:假设有一个方法popAll()方法,从Stack集合中弹出每个元素,添加到指定集合中去。
//参数dst消费stack里面的值(消费者,消费对象),保证stack里面的对象是dst的父类 public void popAll(Collection<? super E> dst) { while (!isEmpty()) dst.add(pop()); }
JDK里面的代码
/** * Copies all of the elements from one list into another. After the * operation, the index of each copied element in the destination list * will be identical to its index in the source list. The destination * list must be at least as long as the source list. If it is longer, the * remaining elements in the destination list are unaffected. <p> * * This method runs in linear time. * * @param <T> the class of the objects in the lists * @param dest The destination list. * @param src The source list. * @throws IndexOutOfBoundsException if the destination list is too small * to contain the entire source List. * @throws UnsupportedOperationException if the destination list's * list-iterator does not support the <tt>set</tt> operation. */ public static <T> void copy(List<? super T> dest, List<? extends T> src) { int srcSize = src.size(); if (srcSize > dest.size()) throw new IndexOutOfBoundsException("Source does not fit in dest"); if (srcSize < COPY_THRESHOLD || (src instanceof RandomAccess && dest instanceof RandomAccess)) { for (int i=0; i<srcSize; i++) dest.set(i, src.get(i)); } else { ListIterator<? super T> di=dest.listIterator(); ListIterator<? extends T> si=src.listIterator(); for (int i=0; i<srcSize; i++) { di.next(); di.set(si.next()); } } }
总结
- 如果你是想遍历collection,并对每一项元素操作时,此时这个集合时生产者(生产元素),应该使用 Collection<? extends Thing>.
- 如果你是想添加元素到collection中去,那么此时集合时消费者(消费元素)应该使用Collection<? super Thing>
相关推荐
Java泛型通配符是Java编程语言中一个重要的特性,它允许我们在定义泛型类型时使用问号(?)作为占位符,表示任意类型的参数。这种通配符的使用大大提高了代码的灵活性和可复用性,同时也帮助开发者遵循强类型检查的...
* 一个参数通配符的实例 * 说明:对一个包含了数值元素的集合进行汇总运算。在这种情况下,用户并不关心 * 集合中的每一个对象是什么类型,只要它是数值型即可,而且,用户也希望集合中可以 * 存放不同类型的数值...
java泛型常用通配符实例解析 Java泛型是Java 5中引入的一项新特性,可以用来编写泛型代码,使得代码更加灵活和可重用。其中,通配符是泛型中的一种重要概念,本文将详细介绍Java泛型常用通配符实例解析。 1. 限定...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...
接下来,让我们详细讨论 Java 泛型的关键字和通配符。 extends 和 super 的区别 在 Java 泛型中,extends 和 super 是两个重要的关键字,它们分别用于限定类型的上界和下界。 extends 用于限定类型的上界,表示...
Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...
下面我们将详细探讨Java泛型接口的相关知识点。 1. **泛型接口的定义** 泛型接口的定义方式与普通接口类似,只是在接口名之后添加了尖括号`<T>`,其中`T`是一个类型参数,代表某种未知的数据类型。例如: ```java...
下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...
Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...
Java泛型是Java编程语言中的一个强大特性,它允许在定义类、接口和方法时使用类型参数,从而实现参数化类型。这使得代码更加安全、可读性更强,并且能够减少类型转换的必要。在“java泛型的内部原理及更深应用”这个...
6. **基本类型与泛型**:Java泛型不支持原始类型(如int、char)作为类型参数,但可以通过使用专门的通配符如`Integer[]`或`? extends Number`来间接实现。 7. **泛型和多态**:泛型类可以作为其他泛型类或非泛型类...
Java泛型通配符T、E、K、V区别详解 Java泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口...
Java泛型还有通配符,用于表示对类型的限制。例如,`?`表示任何类型,`? extends Number`表示任何Number的子类,这在处理多种类型集合时非常有用。比如,`accept(List)`可以接收`List<Integer>`、`List<Double>`等。...
#### 一、什么是Java泛型? Java泛型(Generics)是一种在编译时确保类型安全的机制,它允许程序员编写类型安全的通用类或方法,而无需进行显式的类型转换。在Java 1.5引入泛型之前,集合类(如`ArrayList`)只能...
- 泛型通配符:例如`?`,表示任意类型。`List<?>`表示可以容纳任何类型的列表。 - 上界通配符:`<? extends T>`限制了只能传入T或T的子类类型的对象。 - 下界通配符:`<? super T>`限制了只能传入T或T的父类类型...