首页 > 解决方案 > 使用映射初始化对象

问题描述

我无法重用地图来创建新对象。地图随着对象的变化而变化:

def map =  [ id: 0, list: [1,2] ]

class Obj {
    int id = 0
    List<Integer> list = new ArrayList<>()
}

for (iterator in 1..10){
    map.id = iterator
    Obj obj = map as Obj
    obj.list.add(iterator)
    println ("Obj.List: ${obj.list.toString()} \nObj.id: ${obj.id}")
    println "map: ${map.list.toString()}"
}

最后一次迭代的输出:

1. Obj.List: [1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 

2. map: [1, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

标签: groovy

解决方案


它发生在您身上,因为您面临传递对列表的引用而不是创建其副本。Groovy 默认添加了 map 构造函数,这个构造函数在类的情况下Obj实际上是一样的:

class Obj {
    int id = 0
    List<Integer> list = new ArrayList<>()

    Obj(Map map) {
        id = map.id
        list = map.list
    }
}

赋值list = map.list意味着obj.listmap.list引用内存中的同一个对象,这就是为什么当你添加一些东西时obj.list它在你访问时也是可用的map.list。至少有两种方法可以修复它。

Obj1.在类中实现自己的构造函数

在这种情况下,请确保obj.list获得他自己的新列表,例如

class Obj {
    int id = 0
    List<Integer> list = new ArrayList<>()

    Obj(Map map) {
        id = map.id
        list = map.list.clone()
    }
}

map.list2.创建对象后用副本覆盖

在某些情况下,您可能希望保持默认构造函数不变。在这种情况下,您可以简单地map.list用列表的新副本覆盖,例如

for (iterator in 1..10){
    map.id = iterator
    Obj obj = map as Obj
    obj.list = map.list.clone()
    obj.list.add(iterator)
    println ("Obj.List: ${obj.list.toString()} \nObj.id: ${obj.id}")
    println "map: ${map.list.toString()}"
}

应用的两个选项都会产生以下控制台输出:

Obj.List: [1, 2, 1] 
Obj.id: 1
map: [1, 2]
Obj.List: [1, 2, 2] 
Obj.id: 2
map: [1, 2]
Obj.List: [1, 2, 3] 
Obj.id: 3
map: [1, 2]
Obj.List: [1, 2, 4] 
Obj.id: 4
map: [1, 2]
Obj.List: [1, 2, 5] 
Obj.id: 5
map: [1, 2]
Obj.List: [1, 2, 6] 
Obj.id: 6
map: [1, 2]
Obj.List: [1, 2, 7] 
Obj.id: 7
map: [1, 2]
Obj.List: [1, 2, 8] 
Obj.id: 8
map: [1, 2]
Obj.List: [1, 2, 9] 
Obj.id: 9
map: [1, 2]
Obj.List: [1, 2, 10] 
Obj.id: 10
map: [1, 2]

推荐阅读