I'm having some trouble in the following code.
public ArrayList<? extends IEvent> getEventsByDateRange(DateTime minStartTime, DateTime minEndTime)
{
ArrayList<? extends IEvent> returnedEvents = new ArrayList<GoogleEvent>();
returnedEvents.add(new GoogleEvent());
return (returnedEvents);
}
This return the following compilation error for the "returnedEvents.add(new GoogleEvent()); line of code":
The method add(capture#1-of ? extends IEvent) in the type
ArrayList is not applicable for the
arguments (GoogleEvent)
The declaration of the class GoogleEvent
is as follows:
public class GoogleEvent implements IEvent {...}
I know there are some tricky parts using generics in Java, thus the wild-cards but I can't seem to figure this out.
Thanks.
Why don't you write:
public List<IEvent> getEventsByDateRange(DateTime minStartTime, DateTime minEndTime)
{
List<IEvent> returnedEvents = new ArrayList<IEvent>();
returnedEvents.add(new GoogleEvent());
return returnedEvents;
}
You don't need to use ? extends IEvent
because by using only IEvent
, Java will dynamically bind the GoogleEvent
class. It's polymorphism.
The solution:
ArrayList<IEvent> returnedEvents = new ArrayList<IEvent>();
The reason of your error is because the compiler is trying to do capture conversion.
In your case returnedEvents
captures some unknown that extends IEvent
(i.e. anything that extends/implements IEvent
) and you're assigning it to a parameterized type GoogleEvent
).
The compiler sees, returnedEvents.add(? extends IEvent)
which doesn't validate with a signature of returnedEvents.add(GoogleEvent)
as the capture placeholder is set on returnedEvents
.
This is not allowed. returnedEvents
contains a list of GoogleEvent
objects and must not be allowed to accept objects that are not GoogleEvent
objects.
Although in your example you happen to be passing a GoogleEvent
, you are doing so by calling a version of add
that accepts anything that implements IEvent
. That add
method simply isn't allowed to be called, because it could result in the list storing things other than GoogleEvent
.
Java wildcards "edit out" methods that would break the rules in this way.
If you need to return that wildcarded list type, an ArrayList<GoogleEvent>
satisfies it fine.
Note this is a complete source file that compiles without error:
import java.util.*;
interface IEvent { }
class GoogleEvent implements IEvent { }
public class Foo {
public ArrayList<? extends IEvent> getEventsByDateRange() {
ArrayList<GoogleEvent> returnedEvents = new ArrayList<GoogleEvent>();
returnedEvents.add(new GoogleEvent());
return (returnedEvents);
}
}
public ArrayList<IEvent> getEventsByDateRange(DateTime minStartTime,
DateTime minEndTime)
{
ArrayList<IEvent> returnedEvents = new ArrayList<IEvent>();
returnedEvents.add(new GoogleEvent());
return (returnedEvents);
}
You cannot writer to a variable which is declared with ? extends ...
. Writing is only allowed when using ? super ...
.
This can be explained by the following example:
List<GoogleEvent> googleEvents = new ArrayList<GoogleEvent>();
ArrayList<? extends IEvent> returnedEvents = googleEvents;
// Would be OK
returnedEvents.add(new GooleEvent());
// Would be OK to the definition of returnedEvents,
// but breaks the googleEvents.
returnedEvents.add(new OtherEvent());
The short solution for you is to declare returnedEvents as List<GoogleEvent>
.