如何在Groovy中深层复制地图地图?字符键是字符串或Ints。值是字符串,原始对象或其他映射,以递归方式。
答案 0 :(得分:26)
这是一个简单的方法:
// standard deep copy implementation
def deepcopy(orig) {
bos = new ByteArrayOutputStream()
oos = new ObjectOutputStream(bos)
oos.writeObject(orig); oos.flush()
bin = new ByteArrayInputStream(bos.toByteArray())
ois = new ObjectInputStream(bin)
return ois.readObject()
}
答案 1 :(得分:6)
我刚刚遇到这个问题,我刚刚发现:
deepCopy = evaluate(original.inspect())
虽然我在Groovy编写的代码不到12小时,但我想知道使用evaluate
是否存在一些信任问题。此外,以上不处理反斜杠。这样:
deepCopy = evaluate(original.inspect().replace('\\','\\\\'))
一样。
答案 2 :(得分:5)
要深入复制类中的每个成员,newInstance()存在于Class对象中。例如,
foo = ["foo": 1, "bar": 2]
bar = foo.getClass().newInstance(foo)
foo["foo"] = 3
assert(bar["foo"] == 1)
assert(foo["foo"] == 3)
参见http://groovy-lang.org/gdk.html并导航到java.lang,Class,最后newInstance方法重载。
<强>更新强>:
我上面的例子最终是一个浅拷贝的例子,但我真正的意思是,一般来说,你几乎总是必须定义你自己的可靠的深拷贝逻辑,可能使用newInstance()方法,如果clone()方法是不够的。以下是几种方法:
import groovy.transform.Canonical
import groovy.transform.AutoClone
import static groovy.transform.AutoCloneStyle.*
// in @AutoClone, generally the semantics are
// 1. clone() is called if property implements Cloneable else,
// 2. initialize property with assignment, IOW copy by reference
//
// @AutoClone default is to call super.clone() then clone() on each property.
//
// @AutoClone(style=COPY_CONSTRUCTOR) which will call the copy ctor in a
// clone() method. Use if you have final members.
//
// @AutoClone(style=SIMPLE) will call no arg ctor then set the properties
//
// @AutoClone(style=SERIALIZATION) class must implement Serializable or
// Externalizable. Fields cannot be final. Immutable classes are cloned.
// Generally slower.
//
// if you need reliable deep copying, define your own clone() method
def assert_diffs(a, b) {
assert a == b // equal objects
assert ! a.is(b) // not the same reference/identity
assert ! a.s.is(b.s) // String deep copy
assert ! a.i.is(b.i) // Integer deep copy
assert ! a.l.is(b.l) // non-identical list member
assert ! a.l[0].is(b.l[0]) // list element deep copy
assert ! a.m.is(b.m) // non-identical map member
assert ! a.m['mu'].is(b.m['mu']) // map element deep copy
}
// deep copy using serialization with @AutoClone
@Canonical
@AutoClone(style=SERIALIZATION)
class Bar implements Serializable {
String s
Integer i
def l = []
def m = [:]
// if you need special serialization/deserialization logic override
// writeObject() and/or readObject() in class implementing Serializable:
//
// private void writeObject(ObjectOutputStream oos) throws IOException {
// oos.writeObject(s)
// oos.writeObject(i)
// oos.writeObject(l)
// oos.writeObject(m)
// }
//
// private void readObject(ObjectInputStream ois)
// throws IOException, ClassNotFoundException {
// s = ois.readObject()
// i = ois.readObject()
// l = ois.readObject()
// m = ois.readObject()
// }
}
// deep copy by using default @AutoClone semantics and overriding
// clone() method
@Canonical
@AutoClone
class Baz {
String s
Integer i
def l = []
def m = [:]
def clone() {
def cp = super.clone()
cp.s = s.class.newInstance(s)
cp.i = i.class.newInstance(i)
cp.l = cp.l.collect { it.getClass().newInstance(it) }
cp.m = cp.m.collectEntries { k, v ->
[k.getClass().newInstance(k), v.getClass().newInstance(v)]
}
cp
}
}
// assert differences
def a = new Bar("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
def b = a.clone()
assert_diffs(a, b)
a = new Baz("foo", 10, ['bar', 'baz'], [mu: 1, qux: 2])
b = a.clone()
assert_diffs(a, b)
我使用@Canonical
作为equals()方法和tuple ctor。请参阅groovy doc Chapter 3.4.2, Code Generation Transformations。
深度复制的另一种方法是使用mixins。假设您希望现有类具有深层复制功能:
class LinkedHashMapDeepCopy {
def deep_copy() {
collectEntries { k, v ->
[k.getClass().newInstance(k), v.getClass().newInstance(v)]
}
}
}
class ArrayListDeepCopy {
def deep_copy() {
collect { it.getClass().newInstance(it) }
}
}
LinkedHashMap.mixin(LinkedHashMapDeepCopy)
ArrayList.mixin(ArrayListDeepCopy)
def foo = [foo: 1, bar: 2]
def bar = foo.deep_copy()
assert foo == bar
assert ! foo.is(bar)
assert ! foo['foo'].is(bar['foo'])
foo = ['foo', 'bar']
bar = foo.deep_copy()
assert foo == bar
assert ! foo.is(bar)
assert ! foo[0].is(bar[0])
或类别(再次参见groovy doc),如果您想要基于某种运行时上下文的深度复制语义:
import groovy.lang.Category
@Category(ArrayList)
class ArrayListDeepCopy {
def clone() {
collect { it.getClass().newInstance(it) }
}
}
use(ArrayListDeepCopy) {
def foo = ['foo', 'bar']
def bar = foo.clone()
assert foo == bar
assert ! foo.is(bar)
assert ! foo[0].is(bar[0]) // deep copying semantics
}
def foo = ['foo', 'bar']
def bar = foo.clone()
assert foo == bar
assert ! foo.is(bar)
assert foo[0].is(bar[0]) // back to shallow clone
答案 3 :(得分:4)
我担心你必须以clone
的方式去做。您可以试试Apache Commons Lang SerializationUtils
答案 4 :(得分:1)
对于Json(LazyMap),这对我来说很困难
copyOfMap = new HashMap<>()
originalMap.each { k, v -> copyOfMap.put(k, v) }
copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(copyOfMap))
编辑:简化:埃德·兰德尔(Ed Randall)
copyOfMap = new JsonSlurper().parseText(JsonOutput.toJson(originalMap))