根据我读过的文献,我们有多汁的实现以下界面:
public interface Juicy<T> {
Juice<T> squeeze();
}
使用有界类型变量,以下方法将获得大量成果并将其全部挤压:
<T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits);
现在我们需要下面的兄弟姐妹来工作:
class Orange extends Fruit implements Juicy<Orange>;
class RedOrange extends Orange;
所以我希望该方法看起来如下:
<T extends Juicy<T>> List<Juice<? super T>> squeeze(List<? extends T> fruits);
相反,我发现方法签名如下:
<**T extends Juicy<? super T>>** List<Juice<? super T>> squeezeSuperExtends(List<? extends T> fruits);
是什么解释了这种差异?
答案 0 :(得分:3)
<? super T>
中的<T extends Juicy<? super T>>
是RedOrange
,Juicy<Orange>
是<? super T>
的子类,可以在其范围内。
想象一下,首先没有public <T extends Juicy<T>> List<Juice<T>> squeeze(List<T> fruits) {...
:
T
现在Juicy<T>
必须是Orange
。班级Juicy<T>
是Juicy<Orange>
,它是RedOrange
。但是课程Juicy<T>
不是Juicy<RedOrange>
。它不是Juicy<Orange>
;它是squeeze
。因此,当我们尝试拨打List<RedOrange> redOranges = new ArrayList<RedOrange>();
List<Juice<RedOrange>> juices = squeeze(redOranges);
时:
Inferred type 'RedOrange' for type parameter 'T' is not within its bound; should implement 'Juicy<RedOrange>'.
我们收到以下编译错误:
<? super T>
如果我们放置Juicy
,则允许T
的类型参数为RedOrange
的超类。这样就可以使用Juicy<Orange>
,因为它是Orange
,而RedOrange
是public <T extends Juicy<? super T>> List<Juice<T>> squeeze(List<T> fruits) {...
的超类。
squeeze
现在上面对squeeze
的调用已编译。
修改强>
但是如果我们想List<Juice<Orange>>
来自List<RedOrange>
Orange
怎么办?它有点棘手,但我找到了解决方案:
我们需要第二个类型参数来匹配squeeze
方法中的public <S extends Juicy<S>, T extends Juicy<S>> List<Juice<S>> squeeze(List<T> fruits)
:
S
此处,Orange
代表List<Juice<Orange>>
,因此我们可以返回List<RedOrange> redOranges = new ArrayList<RedOrange>();
List<Juice<Orange>> juices = squeeze(redOranges);
。现在我们可以说
{{1}}
答案 1 :(得分:3)
在我看来,最简单的思考方法是简单地忽略水果类型与其产生的果汁类型之间的关系。该链接在类声明中建立;我们不需要它来挤压一堆Juicy
s。
换句话说,只需参数化Juice
将产生的Juicy
类型:
<T> List<Juice<T>> squeeze(List<? extends Juicy<? extends T>> fruits);
在这里,我们根据生成的Juice
的常见超类型(即Juicy
的参数)生成果汁列表,而不是常见的超级水果类型。
然后我们得到以下内容:
//works
List<Juice<Orange>> b = squeeze(Arrays.asList(new Orange(), new RedOrange()));
//fails as it should
List<Juice<RedOrange>> d = squeeze(Arrays.asList(new RedOrange()));