1

Parent class:

public class Action
    {
        private String eventId;
        private List<ActionArgument> arguments;
        //action to perform when this action is done
        private List<? extends Action> onCompleteActions;

        public Action(){}

        public Action(String eventId, List<ActionArgument> arguments, List<? extends Action> onCompleteActions)
        {
            this.eventId = eventId;
            this.arguments = arguments;
            this.onCompleteActions = onCompleteActions;
        }

        public String getEventId()
        {
            return eventId;
        }
        public void setEventId(String eventId)
        {
            this.eventId = eventId;
        }
        public List<ActionArgument> getArguments()
        {
            return arguments;
        }
        public void setArguments(List<ActionArgument> arguments)
        {
            this.arguments = arguments;
        }
        public List<? extends Action> getOnCompleteActions()
        {
            return onCompleteActions;
        }
        public void setOnCompleteActions(List<? extends Action> onCompleteActions)
        {
            this.onCompleteActions = onCompleteActions;
        }
    }

extended class:

public class UserDefinedAction extends Action
{
    // body not important
}

Some service:

private boolean arrangeBefore(List<? extends Action> defaultActions, UserDefinedAction action)
    {
        String actionToFind = action.getDoBefore();
        boolean actionFound = false;
        for(int i = 0; i < defaultActions.size(); i++)
        {
            if(defaultActions.get(i).getEventId().toUpperCase().equals(actionToFind.toUpperCase()))
            {
                defaultActions.add(i, action);
                return true;
            }
...

So I have an error here: defaultActions.add(i, action); which says "

add
(int,
capture<? extends com.myPackage.Action>)
in List cannot be applied
to
(int,
com.myPackage.UserDefinedAction)

"

Can someone explain to me why this doesnt work?

3
  • If I do that I get this error:add (int, capture<? extends com.myPackage.Action>) in List cannot be applied to (int, com.myPackage.Action) Commented Aug 8, 2013 at 23:00
  • You can't add anything inside a list with upper bounds - List<? extends Action>. You can only add null, or the elements you previously fetched from it. Commented Aug 8, 2013 at 23:00
  • @RohitJain: "or the elements you previously fetched from it." How does the compiler keep track of that? Commented Aug 8, 2013 at 23:44

3 Answers 3

1

A simple possibility to consider is:

  • Make a defensive copy of the input list in the constructor.
  • Store it simply as a List<Action>.

In general, it's useful to remember the PECS acronym - Producer Extends, Consumer Super. If you want to add elements to a List with a bounded type variable or wildcard, you'd want to express it with super rather than extends. For example, List<? super A> means that the list member type is some superclass of an A.

Sign up to request clarification or add additional context in comments.

2 Comments

+1. List<Action> should work well here. Note that a List<Action> can store subclasses of Action already, no need for a wildcard just for that.
Right. In this particular case, it doesn't seem called for. You could accept an arbitrary List<? super Action> in the constructor, or have a getter that accepts as an argument the List<? super Action> to be filled -- but I don't see how either would be particularly helpful.
0

You cannot pass an argument of any type to a method with a wildcard in it. Here, you have a List<? extends Action>, and you're attempting to add a UserDefinedAction.

But Java doesn't know the exact generic type of your List; it assumes it could be anything, even something like List<SomeOtherAction>. It can't allow you to add a UserDefinedAction to your list for that reason. For this reason, Java disallows you to call such a method.

To get around this, you will need to define a generic type parameter on your Action class:

public class Action<A extends Action>

Then you can replace all <? extends Action> in that class with <E>. This way, an Action<Action> will be able to handle a List<Action>.

Next, define A in UserDefinedAction to be UserDefinedAction. This way, a UserDefinedAction can handle a List<UserDefinedAction>, which will allow you to add a UserDefinedAction.

public class UserDefinedAction extends Action<UserDefinedAction>

Alternatively, you could, for more flexibility, define UserDefinedAction this way:

public class UserDefinedAction<A extends UserDefinedAction> extends Action<A>

... and use a UserDefinedAction<UserDefinedAction> instance. This would allow further subclasses of UserDefinedAction to define the generic type parameter A the way they want.

2 Comments

So what would you recommend for what im trying to do?
Sorry, that wasnt there when I posted my previous comment.
0

You can change the signature of the method and use generics in it:

public <A extends Action> void arrangeBefore(List<A> actionList, A action) {
    actionList.add(action);
}

Note that this change assumes that the methods used from A action in arrangeBefore belongs to Action class only.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.