Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why List<?> can convert to List<E> through method invocation conversion?

Tags:

java

----------- lasted update ---------

I think maybe List<?> and List<E> are the same type when we declare them as a method argument. I tried to convert List<E> to List<?>, it worked fine too:

public static <E> void swap2(List<E> list, int i, int j){
    swapHelper2(list, i ,j);
}

private static void swapHelper2(List<?> list, int i, int j) {
    ...
}

------------ original question ------------

From 《Effective Java》 Item 31 it says:

The idea is to write a private helper method to capture the wildcard type...

'private helper method':

public static void swap(List<?> list, int i, int j) {
    swapHelper(list, i, j);
}
// Private helper method for wildcard capture
private static <E> void swapHelper(List<E> list, int i, int j) { 
    list.set(i, list.set(j, list.get(i)));
}

My question is why List<?> could convert to List<E> through method invocation without compile error?

In my opinion I think List<?> is a SuperType of any List<E>, so it should need some narrowing conversion such as:

List<?> list = new ArrayList<>();
List<String> listOfString = (List<String>)list;
swapHelper(listOfString, 0 ,0);
like image 878
helpmeRein Avatar asked Dec 22 '22 15:12

helpmeRein


2 Answers

What does List<?> really represents? It means "a list containing some unknown type of objects".

What does a method say when it has a type argument <E> as your swapHelper? It says: I accept any arbitrary type E.

We know that the ? above is a some type, we just don't know which one. The <E> accepts any type, so we know that whatever ? represents it can be used as E. That's why you can call swapHelper with a List<?>.

Why can't we do that trick by simply assigning a List<?> variable to a List<E> variable? Because a local variable doesn't have type arguments, those only exist on methods and classes.

So the fact that swapHelper has the unrestricted type variable makes it able to accept a List<?> without anything in the code ever "knowing" what the ? really represents, since it only cares that there is a type, not what that type is.

like image 79
Joachim Sauer Avatar answered Jan 26 '23 00:01

Joachim Sauer


List<?> means "a List whose element type isn't known here".

That's not to say that the element type isn't known at all, just, at this point in the code, you don't know what it is.

But all Lists have some element type (unless they are raw, I suppose). So, a List<?> has some element type, if only you knew what it was.

When you say List<E>, you still don't really know what the type of the element is. You know that it's a subtype of Object, but nothing more than that. However, significantly, you know that if you get an element out of a List<E>, then it's a thing of type E:

E item = list.get(i);

and you know that it would be safe to put that thing back into the list:

list.set(j, item);

You don't know what type E is - but you do know that it's the same type as the elements in the list.

So, you can always pass a List<?> to a generic method (that is, it declares its own type variables) that expects a List<E>, because you're saying that the elements have a consistent type, even if you don't know what it is.

like image 45
Andy Turner Avatar answered Jan 25 '23 23:01

Andy Turner