Private helper method to capture wildcard type for generic methods
以下代码不在Eclipse中编译。它说"abc类型中的方法putHelper(list,int,e)不适用于参数(list<.capture 8-of extends e>",int,e)。
1 2 3 4 5 6 7 8 | private <E> void putHelper(List<E> list, int i, E value) { list.set(i, value); } public <E> void put(List<? extends E> list, int toPos, E value) { // list.set(toPos,value); putHelper(list, toPos, value); } |
我不明白为什么会这样?因为下面的代码工作正常。
1 2 3 4 5 6 7 | public <E> void put(List<? extends E> list,int fromPos, int toPos) { putHelper(list,fromPos,toPos); } private <E> void putHelper(List<E> list,int i, int j) { list.set(j,list.get(i)); } |
号
我理解这里的helper方法能够捕获通配符类型,但是为什么不在前面的代码中呢?
编辑:在第三种情况下,如果我将Put方法中的类型参数更改为List<.?当我试图从另一个获取列表的方法调用put()方法时,Eclipse不会编译它。它说,"方法放(列表<."类型abc中的super e>,int,e)不适用于参数(list<.capture 6-of extends e>",int,e)"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public static <E> void insertAndProcess(List<? extends E> list) { // Iterate through the list for some range of values i to j E value = list.get(i); //Process the element and put it back at some index put(list, i+1, value); //Repeat the same for few more elements } private static <E> void putHelper(List<E> list, int i, E value) { list.set(i, value); } public static <E> void put(List<? super E> list, int toPos, E value) { putHelper(list, toPos, value); } |
在这里,insertandprocess()如何调用put()方法并在其实现中使用它,而用户仍然可以使用arraylist<.integer>调用这两个方法?
这是因为"取得并投入"原则,也就是生产商扩展的缩写pecs,消费者超级。
这在这个问题中得到了解释:什么是PECS(生产者扩展消费者超级)?
但基本上:
1 2 3 4 | public <E> void put(List<? extends E> list, int toPos, E value) { // list.set(toPos,value); putHelper(list, toPos, value); } |
号
这里不能使用
1 2 3 4 | public <E> void put(List<? super E> list, int toPos, E value) { // list.set(toPos,value); putHelper(list, toPos, value); } |
编辑
在第二种情况下,
但是,在第三个示例中,您将得到并放入同一个列表中,因此我认为您根本无法使用通配符。
这编译了:
1 2 3 4 5 6 7 8 9 10 | public static <E> void insertAndProcess(List<E> list) { // Iterate through the list for some range of values i to j E value = list.get(i); // Process the element and put it back at some index putHelper(list, i+1, value); // Repeat the same for few more elements } |
。
注意,由于我们不需要使用任何通配符,因为我们从同一个列表中获取和设置,所以无论类型是什么,
仿制药有时有点困难。试着一步一步地分析它。
想象一下,在第一个示例(不编译)中,您使用类型变量
在第二个示例中,您只对输入参数
解决方案:
始终提醒缩写词pecs。参见通配符(Java)。这意味着您应该声明
1 2 3 | public <E> void put(List<? super E> list, int toPos, E value) { putHelper(list, toPos, value); } |
当你说一个方法只能接受
请注意,在爪哇,这是非法的:
1 | List<E> list = new ArrayList<? extends E>(); |
如
在第二个示例中,您的列表需要e的任何子类,而您传递的是e对象列表,因此它是允许的。如