Java Generics: Wildcard capture misunderstanding
why the compiler can't retain the assignment safe?
The compiler doesn't know anything about the type of elements in List<?> i
, by definition of ?
. Wildcard does not mean "any type;" it means "some unknown type."
It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value.
That's true, but as I said above: the compiler can only know – at compile time, remember – that i.get(0)
returns an Object
, which is the upper bound of ?
. But there's no guarantee that ?
is at runtime Object
, so there is no way for the compiler to know that i.set(0, i.get(0))
is a safe call. It's like writing this:
List<Foo> fooz = /* init */;
Object foo = fooz.get(0);
fooz.set(0, foo); // won't compile because foo is an object, not a Foo
More reading:
- Can't add value to the Java collection with wildcard generic type
- Java Collections using wildcard
- Generic collection & wildcard in java
- Generics - Cannot add to a List with unbounded wildcard
- What is the difference betwen Collection<?> and Collection<T>
why the compiler can't retain the assignment safe? It knows that,by executing for instance, the method with an Integer List, it gets from i.get an Integer value. So it try to set an Integer value at index 0 to the same Integer list (i).
Put differently, why does the compiler not know that the two usages of the wildcard type List<?>
in
i.set(0, i.get(0));
refer to the same actual type?
Well, that would require the compiler to know that i
contains the same instance for both evaluations of the expression. Since i
isn't even final, the compiler would have to check whether i
could possibly have been assigned in between evaluating the two expressions. Such an analysis is only simple for local variables (for who knows whether an invoked method will update a particular field of a particular object?). This is quite a bit of additional complexity in the compiler for rarely manifesting benefits. I suppose that's why the designers of the Java programming language kept things simple by specifying that different uses of the same wildcard type have different captures.