I'm trying to find a reference, ideally from the language standard, as to why casting a container of T to a super-type of the container and a super-type of T does not work, when done in the same statement.
I've tried looking up various combinations of erasure, casting generics, and specific container classes, but can't find an exact duplicate (most only address T and its superclass). I'm particularly interested in what the language standard has to say on the issue and the terminology used for it.
For example, the following is not accepted by the compiler:
final WebappContext context = ...;
final List<FilterRegistration> filters = Lists.newArrayList(
context.addFilter(...), ...
);
Where WebappContext.addFilter
returns a org.glassfish.grizzly.servlet.FilterRegistration
, which implements javax.servlet.FilterRegistration.Dynamic
, which extends FilterRegistration
. The call to Lists.newArrayList
returns an ArrayList<T>
, depending on the type of its arguments.
I get an error like:
Incompatible Types
Required: List<javax.servlet.FilterRegistration>
Found: ArrrayList<org.glassfish.grizzly.servlet.FilterRegistration>
This is despite List
being a superclass of ArrayList
, and FilterRegistration
being a superclass of the Grizzly implementation.
If I change it to:
final WebappContext context = ...;
final List<FilterRegistration> filters = Lists.<FilterRegistration>newArrayList(
context.addFilter(...), ...
);
Then everything is perfectly happy, not even an unchecked warning. The only change I can find is the return type goes from ArrrayList<org.glassfish.grizzly.servlet.FilterRegistration>
to ArrrayList<javax.servlet.FilterRegistration>
.
I know C++ has a rule that the compiler may only perform a single cast while trying to resolve the best type for a particular call. This seems to behave in the same manner, but what does Java call it and how are the rules defined? Is it related to type erasure, and how so?