Note 1: Generics are invariant! There are lots of articles in the web that discuss that topic.
Note 2: You are using generics in two "layers" of your data structure. That will sometimes be confusing.
Your problem is the following: You are creating subtypes of the Command type with your anonymous class declarations. But you limit the value type in the inner map declaration of your directory to Command only. With the following variation you also allow subtypes:
Map<String, Map<String, ? extends Command<?>>> mappingDirectory = ...
Now you can (and should) declare
Map<String, Command<ClassOne>> classOneMappings = ...
and put it into the directory:
mappingDirectory.put("...", classOneMappings);
(Note that I used only the interface type Map.)
EDIT:
For the following example, I will use the classes Number
, Integer
, and Double
(all in package java.lang
). They are doing their job just fine here. I will also use Java 7 to have the nice type inference when instantiating generics.
I'll start with the Command
interface:
interface Command<T extends Number> {
void run(T number, String field);
}
With that you are able to do the following:
class NestedGenerics {
private static final Map<String, Map<String, ? extends Command>> DIRECTORY = new HashMap<>();
public static void main(String[] args) {
Map<String, Command<Integer>> integerMap = new HashMap<>();
Map<String, Command<Double>> doubleMap = new HashMap<>();
integerMap.put("integer_command", new Command<Integer>() {
@Override
public void run(Integer number, String field) {
System.out.println(field + ": " + number);
}
});
doubleMap.put("double_command", new Command<Double>() {
@Override
public void run(Double number, String field) {
System.out.println(field + ": " + number);
}
});
DIRECTORY.put("integers", integerMap);
DIRECTORY.put("doubles", doubleMap);
DIRECTORY.get("integers").get("integer_command").run(Integer.valueOf(42), "integer field");
DIRECTORY.get("doubles").get("double_command").run(Double.valueOf(42.0), "double field");
}
}
A little disadvantage here is, that you use the Command
type as a raw type in the directory's declaration. But as you are putting various maps with various Command
subtypes into this directory, the Command
class' bound to Number
(remind: T extends Number
) might be enough for the usage.
This example compiles and runs just fine. Its output is:
integer field: 42
double field: 42.0