[Java] - κΉμ 볡μ¬(Deep Copy) vs μμ 볡μ¬(Shallow Copy)
π Java κΉμ 볡μ¬(Deep Copy)μ μμ 볡μ¬(Shallow Copy)
μλ νμΈμ! μ΄λ²μ μ 리ν λ΄μ©μ μλ°μμμ κΉμ 볡μ¬μ μμ λ³΅μ¬ μ λλ€.
κΉμ 볡μ¬μ μμ 볡μ¬λΌλ κ°λ μ νμμ μ νμ μ΄ κ½€ μμμ΅λλ€.
νμ§λ§ μ€λ μκ³ λ¦¬μ¦ λ¬Έμ λ₯Ό νλ©΄μ μλ¬΄λ° μμ¬μμ΄(?) λ€μκ³Ό κ°μ΄ 컬λ μ Listλ₯Ό μμ 볡μ¬νλ μ½λλ₯Ό μμ±νμκ³ , μ΄μ λ°λΌ μ°Έμ‘°νκ³ μλ λ 리μ€νΈκ° λͺ¨λ κ°μ΄ λ³κ²½λμ΄ μκ°νλ μμνκ³Ό λ€λ₯΄κ² λμμ μ½κ° μ΄λ¦¬λ₯μ ν μνμμ΅λλ€. π€
List<String> list = new ArrayList<>();
...
List<String> temp = list; // shallow copy
ν΄λΉ λ¬Έμ μ μ λλ²κΉ μ ν΅ν΄ νμ ν μ μμλλ°μ, κΈ°λ³Έμ μΈ λ΄μ©μ΄μ§λ§ νμ€νκ² μ 리νκ³ λμ΄κ°λλ‘ νκ² μ΅λλ€ π
κΉμ 볡μ¬(Deep Copy)λ 'μ€μ κ°'μ μλ‘μ΄ λ©λͺ¨λ¦¬ 곡κ°μ 볡μ¬νλ κ²μ μλ―Ένλ©°,
μμ 볡μ¬(Shallow Copy)λ 'μ£Όμ κ°'μ 볡μ¬νλ€λ μλ―Έμ λλ€.
μμ 볡μ¬μ κ²½μ° μ£Όμ κ°μ 볡μ¬νκΈ° λλ¬Έμ, μ°Έμ‘°νκ³ μλ μ€μ κ°μ κ°μ΅λλ€.
μμ μ μ€λͺ μ ν΅ν΄ νμΈν΄λ³΄κ² μ΅λλ€.
π― μμ 볡μ¬(Shallow Copy)
public class CopyObject {
private String name;
private int age;
public CopyObject() {
}
public CopyObject(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CopyObjectTest {
@Test
void shallowCopy() {
CopyObject original = new CopyObject("JuHyun", 20);
CopyObject copy = original; // μμ 볡μ¬
copy.setName("JuBal");
System.out.println(original.getName());
System.out.println(copy.getName());
}
}
μ μ½λμμλ copy κ°μ²΄μ setλ©μλλ₯Ό ν΅ν΄ μ΄λ¦μ λ³κ²½νλλ°,
μ€μ κ²°κ³Όλ original κ°μ²΄μ copy κ°μ²΄ λͺ¨λ κ°μ΄ λ³κ²½μ΄ λμμ΅λλ€.
CopyObject copy = original μ μ½λμμ κ°μ²΄μ μμ 볡μ¬λ₯Ό ν΅ν΄ 'μ£Όμ κ°'μ λ³κ²½νκΈ° λλ¬Έμ
μ°Έμ‘°νκ³ μλ μ€μ κ°μ λμΌνκ³ , 볡μ¬ν κ°μ²΄κ° λ³κ²½λλ€λ©΄ κΈ°μ‘΄μ κ°μ²΄λ λ³κ²½μ΄ λλ κ²μ λλ€.
μ μνμ λν λ©λͺ¨λ¦¬ ꡬ쑰λ₯Ό λνλ΄λ©΄ λ€μκ³Ό κ°μ΄ λ©λλ€.
CopyObject original = new CopyObject("JuHyun", 20);
CopyObject copy = original;
μ€νμ΄ μ€νΈμΌλ‘ 보μ΄λ건 λ°°κ° κ³ νμμΌκΉμ..
original μΈμ€ν΄μ€λ₯Ό μμ±νλ©΄ Stack μμμ μ°Έμ‘°κ°μ΄, Heap μμμ μ€μ κ°μ΄ μ μ₯μ΄ λ©λλ€.
κ·Έλ¦¬κ³ μμ 볡μ¬λ₯Ό ν΅ν΄ κ°μ²΄λ₯Ό 볡μ¬νκΈ° λλ¬Έμ copy μΈμ€ν΄μ€λ original μΈμ€ν΄μ€κ° μ°Έμ‘°νκ³ μλ
Heap μμμ μ°Έμ‘°κ°μ λμΌνκ² λ°λΌλ³΄κ³ μλ μνκ° λ©λλ€.
κ·Έ ν set λ©μλλ₯Ό ν΅ν΄ κ°μ λ³κ²½νλ©΄ λμΌν μ£Όμλ₯Ό μ°Έμ‘°νκ³ μκΈ° λλ¬Έμ μλμ κ°μ΄ λ©λλ€.
λ°λΌμ μ½λλ‘λ copy κ°μ²΄μ nameλ§ λ³κ²½νμ§λ§,
λμΌν μ£Όμλ₯Ό μ°Έμ‘°νκ³ μκΈ° λλ¬Έμ originalμ κ°μ²΄μλ μν₯μ λΌμΉκ² λ©λλ€.
κ·Έλμ κ°μ²΄λ₯Ό μΆλ ₯ν΄λ³΄λ©΄ μλμ κ°μ΄ λμΌν μ£Όμκ° μΆλ ₯μ΄ λ©λλ€.
CopyObject original = new CopyObject("JuHyun", 20);
CopyObject copy = original;
System.out.println(original);
System.out.println(copy);
π― κΉμ 볡μ¬(Deep Copy)
κΉμ 볡μ¬λ₯Ό ꡬννλ λ°©λ²μ μ¬λ¬κ°μ§κ° μμ΅λλ€.
- Cloneable μΈν°νμ΄μ€ ꡬν
- λ³΅μ¬ μμ±μ
- λ³΅μ¬ ν©ν°λ¦¬ λ±λ±....
β Cloneable μΈν°νμ΄μ€ ꡬν
Cloneable μΈν°νμ΄μ€λ μμ κ°μ΄ λΉ κ»λ°κΈ°μ μΈν°νμ΄μ€μ§λ§
μ£Όμμ μ΄ν΄λ³΄λ©΄ Object ν΄λμ€μ clone() λ©μλλ₯Ό λ°λμ ꡬννλΌκ³ μ€λͺ μ΄ λμ΄μμ΅λλ€.
public class CopyObject implements Cloneable {
private String name;
private int age;
public CopyObject() {
}
public CopyObject(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected CopyObject clone() throws CloneNotSupportedException {
return (CopyObject) super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Test
void shallowCopy() throws CloneNotSupportedException {
CopyObject original = new CopyObject("JuHyun", 20);
CopyObject copy = original.clone();
copy.setName("JuBal");
System.out.println(original.getName());
System.out.println(copy.getName());
}
κΉμ 볡μ¬λ₯Ό ν΅ν΄ ν μ€νΈλ₯Ό μ§νν΄λ³΄λ©΄ μμ 볡μ¬μλ λ¬λ¦¬ original μΈμ€ν΄μ€μ κ°μ λ³κ²½μ΄ λμ§ μμ΅λλ€.
β» Effective Java 13μ₯μμλ clone μ¬μ μλ μ£Όμν΄μ μ§ννλΌ λΌλ μμ΄ν μ΄ μμ΅λλ€.
ν΄λΉ μ± μ λ΄μ©μ λλ΅μ μΌλ‘ μ΄ν΄λ³΄λ©΄ λ€μκ³Ό κ°μ΅λλ€.
Cloneable μΈν°νμ΄μ€λ 볡μ ν΄λ λλ ν΄λμ€μμ λͺ μνλ μ©λμ λ―Ήμ€μΈ μΈν°νμ΄μ€μ§λ§, μμ½κ²λ μλν λͺ©μ μ μ λλ‘ μ΄λ£¨μ§ λͺ»νλ€. μ¬κΈ°μ ν° λ¬Έμ μ μ clone λ©μλκ° μ μΈλ κ³³μ΄ Cloneableμ΄ μλ OBjectμ΄κ³ , κ·Έ λ§μ λ protectedμ΄λ€. κ·Έλμ Cloneableμ ꡬννλ κ²λ§μΌλ‘λ μΈλΆ κ°μ²΄μμ clone λ©μλλ₯Ό νΈμΆν μ μλ€. 리νλ μ μ μ¬μ©νλ©΄ κ°λ₯νμ§λ§, 100% μ±κ³΅νλ κ²λ μλλ€.
μ΄λ¬ν μ¬λ¬ λ¬Έμ μ μ κ°μ§ μΈν°νμ΄μ€μ΄μ§λ§, Cloneable λ°©μμ λ리 μ°μ΄κ³ μμ΄μ μ μμλλ κ²μ΄ μ’λ€.
Cloneableμ΄ λͺ°κ³ μ¨ λͺ¨λ λ¬Έμ λ₯Ό λμ§μ΄λ΄€μ λ, μλ‘μ΄ μΈν°νμ΄μ€λ₯Ό λ§λ€ λλ μ λ Cloneableμ νμ₯ν΄μλ μ λλ©°, μλ‘μ΄ ν΄λμ€λ μ΄λ₯Ό ꡬνν΄μλ μλλ€. final ν΄λμ€λΌλ©΄ Cloneableμ ꡬνν΄λ μνμ΄ ν¬μ§λ μμ§λ§, μ±λ₯ μ΅μ ν κ΄μ μμ κ²ν ν ν λ³λ€λ₯Έ λ¬Έμ κ° μμ λλ§ λλ¬Όκ² νμ©ν΄μΌ νλ€.
κΈ°λ³Έ μμΉμ '볡μ κΈ°λ₯μ μμ±μμ ν©ν°λ¦¬λ₯Ό μ΄μ©νλκ² μ΅κ³ ' λΌλ κ²μ΄λ€.
λ¨, λ°°μ΄λ§μ clone λ©μλ λ°©μμ΄ κ°μ₯ κΉλν, μ΄ κ·μΉμ ν©λΉν μμΈλΌ ν μ μλ€.
β λ³΅μ¬ μμ±μ, λ³΅μ¬ ν©ν°λ¦¬
public class CopyObject {
private String name;
private int age;
public CopyObject() {
}
/* λ³΅μ¬ μμ±μ */
public CopyObject(CopyObject original) {
this.name = original.name;
this.age = original.age;
}
/* λ³΅μ¬ ν©ν°λ¦¬ */
public static CopyObject copy(CopyObject original) {
CopyObject copy = new CopyObject();
copy.name = original.name;
copy.age = original.age;
return copy;
}
public CopyObject(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Test
void shallowCopy() {
CopyObject original = new CopyObject("JuHyun", 20);
CopyObject copyConstructor = new CopyObject(original);
CopyObject copyFactory = CopyObject.copy(original);
copyConstructor.setName("JuBal");
copyFactory.setName("BalJu");
System.out.println(original.getName());
System.out.println(copyConstructor.getName());
System.out.println(copyFactory.getName());
}
λ³΅μ¬ μμ±μμ λ³΅μ¬ ν©ν°λ¦¬λ₯Ό ν΅ν΄ κ°μ²΄λ₯Ό 볡μ¬νλ κ³Όμ λ κΉμ 볡μ¬μμ μ μ μμ΅λλ€.
κΉμ 볡μ¬λ₯Ό κ·Έλ¦ΌμΌλ‘ λνλ΄λ©΄ λ€μκ³Ό κ°μ΅λλ€.
μμ 볡μ¬μλ λ€λ₯΄κ² Heap μμμ μλ‘μ΄ λ©λͺ¨λ¦¬ 곡κ°μ μμ±νμ¬ μ€μ κ°μ 볡μ¬ν©λλ€.
Collectionsλ Mapμ κ²½μ° μ΄λ―Έ λ³΅μ¬ ν©ν°λ¦¬μΈ copy() λ©μλλ₯Ό ꡬννκ³ μμ΅λλ€.
/**
* Copies all of the elements from one list into another. After the
* operation, the index of each copied element in the destination list
* will be identical to its index in the source list. The destination
* list's size must be greater than or equal to the source list's size.
* If it is greater, the remaining elements in the destination list are
* unaffected. <p>
*
* This method runs in linear time.
*
* @param <T> the class of the objects in the lists
* @param dest The destination list.
* @param src The source list.
* @throws IndexOutOfBoundsException if the destination list is too small
* to contain the entire source List.
* @throws UnsupportedOperationException if the destination list's
* list-iterator does not support the {@code set} operation.
*/
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else {
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}