Wenn wir ein Objekt in Java kopieren möchten, müssen wir zwei Möglichkeiten berücksichtigen: eine flache Kopie und eine tiefe Kopie .
Die flache Kopie ist der Ansatz, wenn wir nur Feldwerte kopieren. Daher kann die Kopie vom Originalobjekt abhängig sein. Beim Deep Copy- Ansatz stellen wir sicher, dass alle Objekte im Baum tief kopiert werden, sodass die Kopie nicht von einem früheren vorhandenen Objekt abhängig ist, das sich jemals ändern könnte.
Diese Frage ist die perfekte Definition für die Anwendung des Deep-Copy- Ansatzes.
Wenn Sie eine einfache HashMap<Integer, List<T>>
Karte haben, erstellen wir zunächst eine solche Problemumgehung. Erstellen einer neuen Instanz des List<T>
.
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;
}
Dieser verwendet eine Stream.collect()
Methode zum Erstellen der Klonzuordnung, verwendet jedoch dieselbe Idee wie die vorherige Methode.
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())));
}
Wenn die darin enthaltenen Instanzen T
jedoch auch veränderbare Objekte sind , haben wir ein großes Problem. In diesem Fall ist eine wirklich tiefe Kopie eine Alternative, die dieses Problem löst. Sein Vorteil ist, dass mindestens jedes veränderbare Objekt im Objektgraphen rekursiv kopiert wird. Da die Kopie nicht von einem zuvor erstellten veränderlichen Objekt abhängig ist , wird sie nicht versehentlich geändert, wie wir es bei der flachen Kopie gesehen haben.
Um das zu lösen, werden diese Deep Copy-Implementierungen die Arbeit erledigen.
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;
}
}