2014-01-29 25 views
0

林集合:避免原始类型与不同类型的具有下列情形

我用command模式类似如下:

public interface Command<T extends EObject> 
{ 
void runCommand(T classToMap, String fieldForMapping); 
} 

正如有人可能会注意到,我与Eclipse Modelling Framework工作,但这对这个问题无关紧要。

在另一个类中,我有一个HashMap作为mappingDirectory,该键返回另一个Map。

private final static HashMap<String, LinkedHashMap<String, Command>> mappingDirectory = new HashMap<String, LinkedHashMap<String, Command>>(); 

对此mappingDirectory我添加各种地图看起来像这样:

private final static LinkedHashMap<String, Command> classOneMappings = new LinkedHashMap<String, Command>(); 
private final static LinkedHashMap<String, Command> classTwoMappings = new LinkedHashMap<String, Command>(); 

...等等。这些地图充满了密钥和所提到的命令接口:

classOneMappings.put("someKey", new Command<ClassOne>() 
    { 
    @Override 
    public void runCommand(ClassOne classToMap, String fieldForMapping) 
    { 
     classToMap.setName(fieldForMapping); 
    }; 
    }); 

最后我有很多不同类型的实现命令接口。那么我怎样才能避免使用Command作为mappingDirectory的原始类型和包含的地图?

我认为这将有可能得到这个工作是这样的:

HashMap<String, LinkedHashMap<String, Command<? extends EObject>>> mappingDirectory = new HashMap<String, LinkedHashMap<String, Command<? extends EObject>>>(); 

,并与他们的具体类型它们所有EObjects声明其他地图:

private final static LinkedHashMap<String, Command<ClassOne>> classOneMappings = new LinkedHashMap<String, Command<ClassOne>>(); 

但可悲的是把他们进入mappingDirectory将导致编译错误。

也许我只是俯瞰一些东西,所以任何帮助将不胜感激!

回答

1

注1 :泛型是不变的!网上有很多文章讨论这个话题。

注2:您在数据结构的两个“层”中使用泛型。这有时会令人困惑。

您的问题如下:您正在使用匿名类声明创建Command类型的子类型。但是,将目录的内部映射声明中的值类型限制为仅命令。用下面的变化也让亚型:

Map<String, Map<String, ? extends Command<?>>> mappingDirectory = ... 

现在你可以(也应该)宣布

Map<String, Command<ClassOne>> classOneMappings = ... 

,并把它放入目录:

mappingDirectory.put("...", classOneMappings); 

(请注意,我用只有接口类型为Map)


编辑:

在以下示例中,我将使用的类NumberInteger,和Double(所有在包java.lang)。他们在这里工作得很好。在实例化泛型时,我还将使用Java 7进行很好的类型推断。

我会与Command界面开始:

interface Command<T extends Number> { 
    void run(T number, String field); 
} 

有了,你能做到以下几点:

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"); 
    } 
} 

有点吃亏在这里,您使用Command类型目录声明中的原始类型。但是,当您将各种Command子类型的各种地图放入此目录中时,Command类别绑定到Number(提醒:T extends Number)可能足以满足使用要求。

这个例子编译并运行得很好。它的输出是:

integer field: 42

double field: 42.0

+0

感谢您的时间:)这可悲的结果是与Rohits建议相同的问题:编译错误,抱怨说我不能用EObject调用runCommand方法。有关更多详情,请参阅下面的Rohits建议的第一条评论。 – Ben

+0

好吧,在这种情况下唯一的办法是将变量'mappingDirectory'声明为'Map >'。我会编辑我的答案。希望这可以帮助。 – Seelenvirtuose

+0

好吧,那比以前好多了。我想这不能在不改变结构本身的情况下进一步加强。谢谢! :) – Ben

2

最外层通配符和嵌套通配符之间的区别在于,嵌套通配符不捕获。

考虑以下两个声明:

List<? extends Number> list = new ArrayList<Integer>();  // 1 
List<List<? extends Number>> list2 = new ArrayList<List<Integer>>(); // 2 

List<List<? extends Number>> list3 = new ArrayList<List<? extends Number>>();// 3 

虽然第一个声明是完全合法的,因为我们知道,List<? extends Number>可以捕捉ArrayList<Integer>,第二个声明是无效的。 A List<List<? extends Number>>,不捕获ArrayList<List<Integer>>。你只能使用第三个声明。

因此,应用相同的逻辑来您的地图,如果你已经声明了一个Map这样的:

private static HashMap<String, LinkedHashMap<String, Command<? extends EObject>>> mappingDirectory = 
     new HashMap<String, LinkedHashMap<String, Command<? extends EObject>>>(); 

只能添加到他们Map这样的:

private static LinkedHashMap<String, Command<? extends EObject>> classOneMappings = 
     new LinkedHashMap<String, Command<? extends EObject>>(); 
private static LinkedHashMap<String, Command<? extends EObject>> classTwoMappings = 
     new LinkedHashMap<String, Command<? extends EObject>>(); 
+0

感谢您的时间Rohit。我也试过这样,但试图调用一个方法:'mappingDirectory.get(0).runCommand(eObject,fields [i]);'结果到以下编译错误:'方法runCommand(capture#69-of?扩展EObject,字符串)的类型Command 不适用于参数(EObject,String)'。这个错误很让我困惑...... – Ben

+0

@Ben你的'runCommand'方法是怎么样的。向我展示代码,您在哪里填充内部地图。 –

+0

代码应该在我的答案中,部分'classOneMappings.put(“someKey”,新命令()...'或者我错过了什么吗? – Ben