Reputation: 1647
Java's 8 method signature looks as follows:
public static <E extends CharSequence> List<? super E> m(List<E> list);
And somewhere in code, method call:
result = m(list);
Suppose that I've create argument list
as follows:
List<String> list = new ArrayList<>();
My question is, why the result
can be just raw List
, and can't be even a List<Object>
?
Upvotes: 2
Views: 1885
Reputation: 20618
Calling your method with a List<String>
as an argument is like calling the following method:
public static List<? super String> m(List<String> list) { ... }
Consider the following starting code:
List<String> list = new ArrayList<>();
List<? super String> result = m(list);
This calls the above mentioned method and stores the return value into the variable result
- which is typed exactly with the method's return type.
The question now is: To what variables - or better what types - can you assign this variable? So we are speaking about assignment compatibility.
Consider these assignments:
List<String> result1 = result; // compiler error: type mismatch (not assignable)
List<Object> result2 = result; // compiler error: type mismatch (not assignable)
List result3 = result; // ok
List<?> result4 = result; // ok
List<? super String> result5 = result; // ok
List<? extends Object> result6 = result; // ok
To understand the nature of this error, you must know that generics are invariant. That means, the type List<String>
is not a subtype of List<Object>
- although the types String
and Object
have such a subtype hierarchy.
So, what we are trying here is:
List<? super String>
to a List<String>
=> fails, no subtypingList<? super String>
to a List<Object>
=> fails, no subtypingList<? super String>
to a List
=> succeeds, because using raw types opts out from type checking generallyList<? super String>
to a List<?>
=> succeeds, because a List<?>
is the supertype of all List<...>
List<? super String>
to a List<? super String>
=> succeeds, because ... well ...List<? super String>
to a List<? ectends Object>
=> succeeds, because List<? ectends Object>
is essentially the same as List<?>
.Note, that trying to assign a List<? super String>
to a List<? super CharSequence>
or a List<? extends CharSequence>
will also fail. They are not in a subtype hierarchy.
Why is that so? The compiler cannot guarantee that the actual list was instantiated with a type that matches the constraint ? super/extends CharSequence
.
Upvotes: 3
Reputation: 12932
The reason you can't do that is because Java generics are not covariant. That is, List<Object>
is not a super-class of List<String>
. The method signature of your method m
would however allow returning a List<String>
, and then you would have a List<Object>
typed reference pointing to List<String>
. Since generic type information is not available at run time, this would not raise an exception immediately, but it could result in type errors in unrelated places.
For example, suppose m
is implemented as follows:
private static List<CharSequence> theResult = new ArrayList<>();
public static <E extends CharSequence> List<? super E> m(List<E> list) {
theResult.addAll(list);
return theResult;
}
Then using your method as follows would ad a non-CharSequence
object to a List<CharSequence>
:
List<Object> os = m(someList);
os.add(new Object());
Luckily, the above does not compile.
Upvotes: 1