java 有界泛型_Java泛型(有界通配符)

根据Joshua Bloch的"有效Java"一书,有一个关于如何/何时使用泛型中的有界通配符的规则。这条规则是PECS(生产者扩展,Comsumer Super)。当我研究以下例子时:

Stack numberStack = new Stack();

Iterable integers = ... ;

numberStack.pushAll(integers);

我知道这个规则非常适合这个例子。我必须将方法pushAll声明为以下示例:

// Wildcard type for parameter that serves as an E producer

public void pushAll(Iterable extends E> src) {

for (E e : src)

{

push(e);

}

}

但是如果我有下面的例子会发生什么呢?

Stack integerStack = new Stack();

Iterable numbers = ... ;

integerStack.pushAll(numbers);

我必须按以下方式申报pushAll:

public void pushAll(Iterable super E> src) {

for (E e : src)

{

push(e);

}

}

根据PECS规则,上述声明是错误的。但我想得到一个Stack的Integers,并把它传给这个Stack的Number。为什么不做呢?为什么我总是使用extends关键字?为什么使用super是错误的?当然,这也代表了康萨姆的观点。为什么消费者应该一直是super?

附:更具体地说,你可以在参考书的"第28项"部分找到上述例子。

当你推-你作为一个消费者,而不是生产者,所以你需要使用超级关键字。

根据这本书,我是制片人。注释"作为e生产者的参数的通配符类型"由编写器提供。作者说,当我拉到那堆东西的时候,我是一个同志!前两个样本来自这本书(复制粘贴)。第三个例子是我的。

当您声明一个Stack时,您的意思是一堆foo或foo的子类。例如,您希望能够将String放入Stack中。另一种方法是不正确的,您不能在Stack中插入另一个对象。

在您的示例中,您声明一个Stack。您应该能够在这个堆栈中放入整数,但不能放入其他数字(比如双精度数),如果声明参数super E>,就可以这样做。这就是为什么put方法应该有一个extends E>类型的参数。

试图在堆栈中存储任意数字是不可能的,因为一个数字可能是另一个整数。所以你的例子没有多大意义。

当对象asts作为使用者时,即当对象的泛型类型的实例作为参数传递给对象的方法时,可以使用super。例如:

Collections.sort(List, Comparator super T>)

在本例中,sort方法从集合中获取T实例,并将它们作为参数传递给comparator的compare(T o1, T o2)。

与您的第一个例子相比,在这个例子中,不可重复的src是一个生产者。pushAll()方法调用iterable的方法,它产生(即返回)t的实例。在这种情况下,iterable是一个生产者,因此使用? extends T。

你的例子没有多大意义。像extends Number>这样的结构意味着数字和每种类型都可以从数字中得到。所以定义一个上下边界,从类型编号到最具体的类型编号。另一方面,super Number>意味着允许使用数字及其任何超数。由于编号扩展了对象并实现了可序列化,因此允许以下三种类型:

java.lang.number号

java.lang.object对象

java.io.serializable可序列化

在您的示例中,您声明了通用类型Stack。让我们考虑下面的内容。

您的堆栈永远无法保存任何超类型整数的项

您的堆栈永远无法保存任何整数子类型的项,因为整数类是最终的,因此它不能被子类化。

因此,如果您想要声明通用类型Stack,那么您的iterable是Iterable类型,因此您的堆栈只能保存integer类型的项。你对助记符pecs完全正确,但这只在你选择了一个具体类型时有效,它至少有一个超级类型和至少一个子类型。

首先要注意的是,整数扩展了数字,所以不应该将数字对象推到整数堆栈中。但是,第一个示例将处理整数、浮点数、bigdecimal和所有其他数字子类。

在pushAll方法中,您不传递类型E,而是传递扩展E的任何类型。因此,您可以通过扩展Number的任何类型的Iterable,而不是通过Number的Iterable。

原始示例使用Number类型,因为您随后可以传递属于Number子类的任何类型,如Integer和BigDecimal等。

在您的示例中,您是以另一种方式进行的。你用Integer申报你的Stack。因此,pushAll只能接受由Integer扩展的类。您将无法使用Numbers(或任何其他类,因为Integer是最终类)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值