Generic: ArrayList of ? Extends ISomeInterface in Java

2k Views Asked by At

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.

6

There are 6 best solutions below

6
On BEST ANSWER

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;
}
6
On

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);
    }
}
0
On

You don't need to use ? extends IEvent because by using only IEvent, Java will dynamically bind the GoogleEvent class. It's polymorphism.

2
On

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.

0
On
public ArrayList<IEvent> getEventsByDateRange(DateTime minStartTime,
        DateTime minEndTime)
{
    ArrayList<IEvent> returnedEvents = new ArrayList<IEvent>();
    returnedEvents.add(new GoogleEvent());
    return (returnedEvents);
}
3
On

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>.