我正在尝试使用Groovy方法创建具有默认值的TreeMap<String, List<Data>>
,因此如果密钥尚未存在,我可以轻松地将数据添加到新列表中。
TreeMap<String, List<Data>> myData = (TreeMap<String, List<Data>>) [:].withDefault { [] }
如您所见,我要求使用TreeMap
而withDefault
只返回Map
个实例,因此我需要进行投射。
当我尝试向地图添加新列表时,
myData[newKey].add(newData)
myData[newKey]
是null
。但是,如果我更改Map
初始化以删除TreeMap
强制转换(并将类型更改为Map
而不是TreeMap
),myData[newKey].add(newData)
将按预期工作。
这是什么原因?如果我投射地图,我可以不使用withDefault
吗?
答案 0 :(得分:2)
问题不在于演员。它还与声明的类型有关。问题可以简化为:
def map1 = [:].withDefault { 0 }
TreeMap map2 = map1
执行该操作时map1
是groovy.lang.MapWithDefault
的实例,map2
是java.util.TreeMap
的实例。它们是堆上的2个独立对象,而不仅仅是指向同一对象的2个引用。 map2
不会有任何与之关联的默认行为。就好像你这样做了:
def map1 = [:].withDefault { 0 }
TreeMap map2 = new TreeMap(map1)
这就是您的代码所发生的事情。演员和泛型只是让你的代码不那么清晰。
此:
TreeMap<String, List<Data>> myData = (TreeMap<String, List<Data>>) [:].withDefault { [] }
可以分解为:
def tmpMap = [:].withDefault { [] }
TreeMap<String, List<Data>> myData = (TreeMap<String, List<Data>>)tmpMap
我希望有所帮助。
修改强>
另一种看待同样事情发生的方法是做这样的事情:
Set names = new HashSet()
ArrayList namesList = names
当第二行执行时,创建一个新的ArrayList,就好像你已经完成ArrayList namesList = new ArrayList(names)
一样。这看起来与您在代码中的内容不同,但同样的事情正在发生。您有一个与它关联的静态类型的引用,并将该引用指向不同类型的对象,Groovy正在创建您声明的类型的实例。在上面这个简单的例子中,声明的类型是ArrayList
。在您的示例中,声明的类型为TreeMap<String, List<Data>>
。