如果我们想在Java中复制一个对象,我们需要考虑两种可能性:浅拷贝和深拷贝。
浅拷贝只复制字段值,因此副本可能依赖于原始对象。而深拷贝则确保树中的所有对象都被深度复制,因此副本不依赖于任何之前存在的对象,这些对象可能会发生变化。
这个问题是应用深拷贝方法的完美定义。
首先,如果你有一个简单的HashMap > map,则可以像这样创建一个解决方法。创建一个新的List实例。
public static <T> HashMap<Integer, List<T>> deepCopyWorkAround(HashMap<Integer, List<T>> original)
{
HashMap<Integer, List<T>> copy = new HashMap<>();
for (Map.Entry<Integer, List<T>> entry : original.entrySet()) {
copy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
return copy;
}
这个方法使用
Stream.collect()
来创建克隆映射,但是与前一种方法的思路相同。
public static <T> Map<Integer, List<T>> deepCopyStreamWorkAround(Map<Integer, List<T>> original)
{
return original
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, valueMapper -> new ArrayList<>(valueMapper.getValue())));
}
但是,如果
T
内部的实例也是
可变对象,我们就会有一个大问题。在这种情况下,真正的深度复制是一种解决该问题的选择。它的优点在于,对象图中每个
可变对象都会被递归地复制。由于复制不依赖于先前创建的任何
可变对象,因此不会像浅复制那样意外地修改。
为了解决这个问题,可以使用深度复制实现。
public class DeepClone
{
public static void main(String[] args)
{
Map<Long, Item> itemMap = Stream.of(
entry(0L, new Item(2558584)),
entry(1L, new Item(254243232)),
entry(2L, new Item(986786)),
entry(3L, new Item(672542)),
entry(4L, new Item(4846)),
entry(5L, new Item(76867467)),
entry(6L, new Item(986786)),
entry(7L, new Item(7969768)),
entry(8L, new Item(68868486)),
entry(9L, new Item(923)),
entry(10L, new Item(986786)),
entry(11L, new Item(549768)),
entry(12L, new Item(796168)),
entry(13L, new Item(868421)),
entry(14L, new Item(923)),
entry(15L, new Item(986786)),
entry(16L, new Item(549768)),
entry(17L, new Item(4846)),
entry(18L, new Item(4846)),
entry(19L, new Item(76867467)),
entry(20L, new Item(986786)),
entry(21L, new Item(7969768)),
entry(22L, new Item(923)),
entry(23L, new Item(4846)),
entry(24L, new Item(986786)),
entry(25L, new Item(549768))
).collect(entriesToMap());
Map<Long, Item> clone = DeepClone.deepClone(itemMap);
clone.remove(1L);
clone.remove(2L);
System.out.println(itemMap);
System.out.println(clone);
}
private DeepClone() {}
public static <T> T deepClone(final T input)
{
if (input == null) return null;
if (input instanceof Map<?, ?>) {
return (T) deepCloneMap((Map<?, ?>) input);
} else if (input instanceof Collection<?>) {
return (T) deepCloneCollection((Collection<?>) input);
} else if (input instanceof Object[]) {
return (T) deepCloneObjectArray((Object[]) input);
} else if (input.getClass().isArray()) {
return (T) clonePrimitiveArray((Object) input);
}
return input;
}
private static Object clonePrimitiveArray(final Object input)
{
final int length = Array.getLength(input);
final Object output = Array.newInstance(input.getClass().getComponentType(), length);
System.arraycopy(input, 0, output, 0, length);
return output;
}
private static <E> E[] deepCloneObjectArray(final E[] input)
{
final E[] clone = (E[]) Array.newInstance(input.getClass().getComponentType(), input.length);
for (int i = 0; i < input.length; i++) {
clone[i] = deepClone(input[i]);
}
return clone;
}
private static <E> Collection<E> deepCloneCollection(final Collection<E> input)
{
Collection<E> clone;
if (input instanceof LinkedList<?>) {
clone = new LinkedList<>();
} else if (input instanceof SortedSet<?>) {
clone = new TreeSet<>();
} else if (input instanceof Set) {
clone = new HashSet<>();
} else {
clone = new ArrayList<>();
}
for (E item : input) {
clone.add(deepClone(item));
}
return clone;
}
private static <K, V> Map<K, V> deepCloneMap(final Map<K, V> map)
{
Map<K, V> clone;
if (map instanceof LinkedHashMap<?, ?>) {
clone = new LinkedHashMap<>();
} else if (map instanceof TreeMap<?, ?>) {
clone = new TreeMap<>();
} else {
clone = new HashMap<>();
}
for (Map.Entry<K, V> entry : map.entrySet()) {
clone.put(deepClone(entry.getKey()), deepClone(entry.getValue()));
}
return clone;
}
}