Consider a class C
that implements an interface I
.
While the following is allowed:
I foo( )
{
return new C( );
}
the following is not:
ArrayList<I> foo( )
{
return new ArrayList<C>( );
}
In the first case, callers expect to get an object implementing the interface
I
and therefore it is correct for foo( )
to return an object of class C
. In the second case, callers expect to get an ArrayList
containing objects implementing the interface I
and therefore it should again be correct for foo( )
to return an ArrayList
containing objects of class C
, right?
Consider what happens if the compiler were to allow such code to compile. Callers can then add objects of another class X
, which also implements the interface I
, to the returned ArrayList
with the result that the original ArrayList
, which is only supposed to contain objects of class C
, now also contains objects of an incompatible class X
!
A better way to define the second case is:
ArrayList<? extends I> foo( )
{
return new ArrayList<C>( );
}
(You can also return an
ArrayList<I>
instead, but that loosens up the definition of the returned object.)
Thanks to Steve Onorato for clearing up my muddied thinking.