How to mix generics and inheritance in order to get the desired result?

My question is not easy to explain in words, fortunately, it is not so difficult to demonstrate. So the bear is with me:

public interface Command<R> { public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command } public abstract class BasicCommand<R> implements Command<R> { } public interface CommandProcessor<C extends Command<?>> { public <R> R process(C<R> command);//this is my question... it illegal to do, but you understand the idea behind it, right? } //constrain BasicCommandProcessor to commands that subclass BasicCommand public class BasicCommandProcessor<C extends BasicCommand<?>> implements CommandProcessor<C> { //here, only subclasses of BasicCommand should be allowed as arguments but these //BasicCommand object should be parameterized by R, like so: BasicCommand<R> //so the method signature should really be // public <R> R process(BasicCommand<R> command) //which would break the inheritance if the interface method signature was instead: // public <R> R process(Command<R> command); //I really hope this fully illustrates my conundrum public <R> R process(C<R> command) { return command.execute(); } } public class CommandContext { public static void main(String... args) { BasicCommandProcessor<BasicCommand<?>> bcp = new BasicCommandProcessor<BasicCommand<?>>(); String textResult = bcp.execute(new BasicCommand<String>() { public String execute() { return "result"; } }); Long numericResult = bcp.execute(new BasicCommand<Long>() { public Long execute() { return 123L; } }); } } 

Basically, I want the general method "process" to determine the type of the universal parameter of the Command object. The goal is to be able to limit the various CommandProcessor implementations to specific classes that implement the command line interface, and at the same time to be able to call the process method of any class that implements the CommandProcessor interface and return an object of the type specified in the parameterized Command object. I'm not sure my explanations are clear enough, so please let me know if further explanation is needed. I think the question is: β€œCan this be done at all?” If the answer is "No", then what would be the best workaround (I thought about my pair, but I would like to get fresh ideas)

+6
java generics inheritance
source share
2 answers

Unfortunately, you cannot do this. Since you want the CommandProcessor interface to CommandProcessor defined in terms of Command , your implementation should be ready to accept any Command instance - generics cannot limit this to the value of BasicCommand - if possible, then the BasicCommandProcessor subclass will not implement the CommandProcessor interface.

Or, on the other hand, given the CommandProcessor interface, it is impossible for generics to ensure that this is called only with instances of BasicCommand . To do this, you would need to know about the implementation and go against the point of polymorphism and interfaces.

You can parameterize the result of the command, but not the specific class of the command.

 public interface Command<R> { public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command } public abstract class BasicCommand<R> implements Command<R> { } public interface CommandProcessor { public <R> R process(Command<R> command); } public class BasicCommandProcessor implements CommandProcessor { public <R> R processBasicCommand(BasicCommand<R> command) { return command.execute(); } public <R> R process(Command<R> command) { return processBasicCommand((BasicCommand<R>)command); } } 

The easiest way is to provide a method that takes on the specific type that you need and call it in a generic method. (See BasicCommandProcessor above.)

+3
source share

Basically, I want the general method "process" to dictate the type of the general parameter of the command object.

This contradicts the notion of defining a command as a type parameter for an application type: when creating an instance of CommandProcessor for C , an actual type can be provided, for example, Command<String> . It would even be possible to provide a non-generic type, e.g.

 class Foo implements Command<String> { ... } 

What will C<R> mean then? Foo<R> ? Command<String><R> ? Command<R> ?

So what are your options? If the CommandProcessor should only work with a specific return type, you can do the following:

 class CommandProcessor<R, C extends Command<R>> { R process(C command); } class FancyCommandProcessor<R, C extends FancyCommand<R>> extends CommandProcessor<R,C> { } 

However, I suspect that you want the CommandProcessor to work with all types of commands. This in itself will not be a problem, just declare:

 <R> R process(FancyCommand<R> command); 

If, however, you also need a subtype between CommandProcessors for different families of commands so that you can override the process , you go beyond the expressiveness of Java generics. In particular, you will need either the equivalent of C ++ template type parameters (which allow you to pass a template as an actual type argument), or the ability to capture a command type parameter taking into account the actual type argument, which, as you know, extends Command, Java does not support .

+1
source share

All Articles