Noufal Panolan
Noufal Panolan

Reputation: 1367

Java Generics: The wildcard(?) as argument and return type

I have the following code segment:

public void reorder(int fromIndex, int toIndex) {
    getElements().add(toIndex, getElements().remove(fromIndex));
}

Here, the method getElements has the return type List<?>. The remove method has the return type ?, and the add method shows its arguments as int index, ? element. So my assumption was, since the return type of remove method and second argument of add method are the same - ? - the method call must succeed. But, I was wrong, the above code segment results in the error:

The method add(int, capture#17-of ?) 
in the type List<capture#17-of ?> 
is not applicable for the arguments (int, capture#18-of ?)

Here, I don't have any direct access to the list, and I don't know it's original type returned by getElements method. All I want here is to remove the item at fromIndex and put it at toIndex. So, how do I achieve that? Also is there anything wrong with my understanding of the generics?

Upvotes: 2

Views: 1631

Answers (3)

Ben Schulz
Ben Schulz

Reputation: 6191

No no no! Use capture:

public void reorder(int fromIndex, int toIndex) {
    reorderWithCapture(getElements());
}

private <E> void reorderWithCapture(List<E> elements) {
    elements.add(toIndex, elements.remove(fromIndex));
}

Upvotes: 4

P&#233;ter T&#246;r&#246;k
P&#233;ter T&#246;r&#246;k

Reputation: 116306

The wildcard ? means any (unknown) type, not one specific type. So the compiler can't verify that the any type used in the remove call is the same as the any type used in the getElements and add calls. This is seen from the error message, where the former is described as capture#18-of ? while the latter is capture#17-of ?. These are seen as two different, unrelated types by the compiler.

Since you apparently can't modify the definition of these methods (although they definitely look fishy based on your description), the least worst option here is probably what @Marko suggests: separate the two steps of the process and use a temp variable with a concrete type parameter (Object) to make the compiler happy.

Upvotes: 1

Marko Topolnik
Marko Topolnik

Reputation: 200296

Just add a cast that makes that ? concrete:

public void reorder(int fromIndex, int toIndex) {
  final List<Object> els = (List<Object>)getElements();
  els.add(toIndex, els.remove(fromIndex));
}

Since you are just rearranging elements within the list, this will never cause any trouble. But I must say there's something wrong with the design if you are seeing that kind of return value.

Upvotes: 2

Related Questions