groovy – 使用withDefault创建Map,在放置元素时导致null

我正在尝试使用Groovy方法创建TreeMap< String,List< Data>>使用默认值,因此如果密钥尚不存在,我可以轻松地将数据添加到新列表中.

TreeMap< String,List< Data>> myData =(TreeMap< String,List< Data>>)[:].withDefault {[]}

如您所见,我需要使用TreeMap,而withDefault只返回一个Map实例,所以我需要强制转换.

当我尝试向地图添加新列表时

myData的[则newkey].新增(newData)

myData [newKey]为null.但是,如果我更改Map initilization以删除TreeMap强制转换(并将类型更改为Map而不是TreeMap),myData [newKey] .add(newData)将按预期工作.

这是什么原因?如果我投射地图,我可以不使用withDefault吗?

最佳答案 问题不仅在于演员.它还与声明的类型有关.问题可以简化为这样的事情:

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>>.

点赞