I am having issues using java generics - specifically, using wildcard capture. Here is a simplified version of the code I have that exhibits the problem I am seeing. It is driving me crazy:
public class Task {
private Action<ActionResult, ? extends ActionSubject> action;
private ActionSubject subject = new ActionSubjectImpl();
private List<ActionResult> list = new ArrayList<>();
public static void main(String[] args) {
Task task = new Task();
task.setAction(new ActionImpl());
task.doAction();
}
public void setAction(Action<ActionResult, ? extends ActionSubject> action) {
this.action = action;
}
public void doAction() {
list.add(action.act(subject));
}
public static class ActionResult { }
public interface Action<T, U> {
public T act(U argument);
}
public interface ActionSubject {
public String getName();
}
public static class ActionImpl implements Action<ActionResult, ActionSubjectImpl>{
@Override
public ActionResult act(ActionSubjectImpl argument) {
// Code that requires ActionSubjectImpl specifically instead of the interface.
// This classes implmentation of action should only support ActionSubjectImpl as an
// argument.
return new ActionResult();
}
}
public class ActionSubjectImpl implements ActionSubject {
@Override
public String getName() {
return "I am a subject";
}
}
}
Package declaration and imports are not included - otherwise this is complete. This does not compile. The problem is with the fragment list.add(action.act(subject));
where I am seeing the error message :
incompatible types: ActionSubject cannot be converted to CAP#1
where CAP#1 is a fresh type-variable:
CAP#1 extends ActionSubject from ? extends ActionSubject
I can see from other posts that helper methods are suggested as a way get things like this to work, but I have not been able to come up with one that works.
The Action action
has the type parameters like so: Action<ActionResult, ? extends ActionSubject>
and the ActionSubject
that I am passing in to the act
method is of interface type 'ActionSubject' and of concrete type 'ActionSubjectImpl' although the code fragment in question will not see the concrete type of course. The second type parameter of Action
should support any type that extends ActionSubject
- and it is fine when I set action
to new ActionImpl()
, where the second type is ActionSubjectImpl
.
I would appreciate any comment on what I am doing wrong here in my definitions and use of generics. I may be missing something basic here. I could code this a different way, but until I understand what is going wrong I won't be able to move on.
Thanks.
Here is your misunderstanding: You said:
The second type parameter of
Action
should support any type that extendsActionSubject
This is not correct. The second type parameter of Action
is constrained to be a specific subclass of ActionSubject
, e.g., MyActionSubject
. So you can't pass in an arbitrary ActionSubject
instance, because that's a more generic type.
If you want to have arbitrary subtypes of ActionSubject
, just use ActionSubject
as the second type parameter instead of ? extends ActionSubject
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With