How to fix this wildcard issue when using java generics?

I'm having problems using java generics - in particular, using wildcards. Here is a simplified version of the code that I have that shows the problem I am seeing. It drives 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"; } } } 

The declaration and import of packages are not included - otherwise it will be completed. This does not compile. The problem is the fragment of list.add(action.act(subject)); where I see 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 offered as a way to make things like this work, but I couldn't come up with one that works.

Action action has the following parameters: Action<ActionResult, ? extends ActionSubject> Action<ActionResult, ? extends ActionSubject> and ActionSubject , which I pass to the act method, have the interface type "ActionSubject" and the concrete type "ActionSubjectImpl", although the code snippet in question will not see the specific type of course. The second parameter of type Action should support any type that extends ActionSubject - and this is normal when I set Action to new ActionImpl() , where the second type is ActionSubjectImpl .

I would appreciate any comments regarding what I am doing wrong here in my definitions and use of generics. Maybe I am missing something here. I could have encoded it differently, but until I understand what is happening, I cannot move on.

Thanks.

+5
source share
1 answer

Here is your misunderstanding: you said:

The second type of Action parameter must support any type that extends ActionSubject

This is not true. The parameter of the second type of Action limited to a specific subclass of ActionSubject , for example, MyActionSubject . Therefore, you cannot pass an arbitrary instance of ActionSubject because it is a more general type.

If you want to have arbitrary subtypes of ActionSubject , just use ActionSubject as a parameter of the second type instead ? extends ActionSubject ? extends ActionSubject .

+10
source

Source: https://habr.com/ru/post/1209476/


All Articles