...

clone ๋ฉ์๋
Object.clone() ๋ฉ์๋๋ ์ธ์คํด์ค ๊ฐ์ฒด์ ๋ณต์ ๋ฅผ ์ํ ๋ฉ์๋๋ก, ํด๋น ์ธ์คํด์ค๋ฅผ ๋ณต์ ํ์ฌ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ์์ฑํด ๊ทธ ์ฐธ์กฐ๊ฐ์ ๋ฐํํ๋ค.
์ด๋ฌํ clone() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์ค๋ฒ๋ผ์ด๋ฉ์ ํด์ผ ๋๋๋ฐ, ์ด๋ ๋ฐ์ดํฐ์ ๋ณดํธ๋ฅผ ์ด์ ๋ก Cloneable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค์ ์ธ์คํด์ค๋ง์ด ์ฌ์ฉํ ์ ์๋ค.
Object ํด๋์ค์ clone() ๋ฉ์๋๋ ๊ธฐ๋ณธ์ผ๋ก protected ์ ๊ทผ ๊ถํ์ ๊ฐ๊ณ ์๊ธฐ ๋๋ฌธ์, ์์ํ์ฌ ๋ฉ์๋๋ฅผ public ์ ๊ทผ์ ์ด์๋ก ์ฌ์ ์ํ์ฌ ์ด๋์๋ ๋ณต์ ๊ฐ ๊ฐ๋ฅํ๋๋ก ํด์ผ ํ๋ค.
import java.lang.Cloneable;
// ๊ฐ์ฒด ๋ณต์ฌ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ Cloneable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ clone์ ์ฌ์ ์ ํด์ผํจ
class Person implements Cloneable {
// ...
// clone ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ
public Object clone() throws CloneNotSupportedException { // CloneNotSupportedException๋ checked exception ์ด๋ผ ๋ฐ๋์ ์์ธ์ฒ๋ฆฌ
return super.clone(); // ๊ธฐ๋ณธ์ ์ผ๋ก ๋ถ๋ชจ์ clone์ ๊ทธ๋๋ก ๋ถ๋ฌ์ ๋ฐํ
}
}
public class Main {
public static void main(String[] args) {
try {
Person p = new Person("ํ๊ธธ๋", 11);
Person p_copy = (Person) p.clone();
} catch(Exception e) {}
}
}
์์ ๋ณต์ฌ vs ๊น์ ๋ณต์ฌ
์๋ฐ์ ๊ฐ์ฒด์ ๊ฐ์ ์ฐธ์กฐ ๋ณ์๋ ์ง์ ๊ฐ์ ์ ์ฅํ๋๊ฒ ์๋ ํ(heap) ์์ญ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๊ทธ์ ์ฃผ์๊ฐ์ ์ ์ฅํ๋ ์์ผ๋ก ๊ตฌ์ฑ๋์ด ์๋ค.
๋ง์ผ int๋ double ๊ฐ์ ๊ธฐ๋ณธํ(primitive) ํ์
์ด ์๋, ๊ฐ์ฒด์ ๊ฐ์ ์ฐธ์กฐํ(reference) ํ์
์ ๋ณ์๋ฅผ ๊ทธ๋๋ก ๋ณต์ ๋ฅผ ํ๋ค๋ฉด ๊ฐ์ด ๋ณต์ฌ๋๋ ๊ฒ์ด ์๋ ์ฃผ์๊ฐ์ด ๋ณต์ฌ๋์ด ๊ฒฐ๊ตญ ๊ฐ์ ํ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ผ๋ณด๋ ๊ผด์ด ๋์ด ๋ฒ๋ฆฐ๋ค.
์ด๋ฌํ ๋ณต์ (๋ณต์ฌ)๋ฅผ '์์ ๋ณต์ฌ(shallow copy)'๋ผ๊ณ ํ๋ฉฐ ์์ ๋ณต์ฌ์์๋ ์๋ณธ์ ๋ณ๊ฒฝํ๋ ค๋ฉด ๋ณต์ฌ๋ณธ๋ ์ํฅ์ ๋ฐ๋๋ค
๋ฐ๋ฉด์ ์๋ณธ์ด ์ฐธ์กฐํ๊ณ ์๋ ํ์ ๋ฐ์ดํฐ๊น์ง ๋ณต์ ํ๋ ๊ฒ์ '๊น์ ๋ณต์ฌ(deep copy)'๋ผ๊ณ ํ๋ฉฐ, ๊น์ ๋ณต์ฌ์์๋ ์๋ณธ๊ณผ ๋ณต์ฌ๋ณธ์ด ์๋ก ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๊ธฐ ๋๋ฌธ์ ์๋ณธ์ ๋ณ๊ฒฝ์ด ๋ณต์ฌ๋ณธ์ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ค.
// ๊ฐ์ฒด ๋ณต์ฌ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ Cloneable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ clone์ ์ฌ์ ์ ํด์ผํจ
class User implements Cloneable {
private String name;
public void setName(String name) {
this.name = name;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Main {
public static void main(String[] args) {
try {
// ์์ ๋ณต์ฌ(shallow copy)
User user = new User();
user.setName("Edward");
User copy = user;
System.out.println(user.hashCode()); // 622488023
System.out.println(copy.hashCode()); // 622488023
System.out.println(user.equals(copy)); // true - ๋์ด ๋์ธํ ํ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๊ธฐ ๋๋ฌธ์
// ๊น์ ๋ณต์ฌ(deep copy)
User user2 = new User();
user2.setName("Edward");
User copy2 = (User) user2.clone();
System.out.println(user2.hashCode()); // 1933863327
System.out.println(copy2.hashCode()); // 112810359
System.out.println(user2.equals(copy2)); // false - ๋์ ๋ณต์ฌ๋์ด ์๊น์๋ง ๊ฐ์ง ๋ค๋ฅธ ํ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ผ๋ณด๊ณ ์๊ธฐ ๋๋ฌธ์
} catch(CloneNotSupportedException e) {
e.printStackTrace();
}
}
}

๊ฐ์ฒด ํํ์ ๋ฐ๋ฅธ ๊น์ ๋ณต์ฌ ์ฃผ์์ฌํญ
์์ ์์ ๋ก ์๋ฒฝํ ๊ฐ์ฒด๊ฐ ๋ณต์ฌ๋์๋ค๊ณ ํด์ ๋งน์ ํ๋ฉด ๋๋ค.
๊ฐ๋จํ ๋จ์ผ ํด๋์ค ํ์ ์ ๋๋ ์์ ๋ฐฉ์๋๋ก ๊ทธ๋๋ก ๋ณต์ ๊ฐ ๊ฐ๋ฅํ์ง๋ง, ํด๋์ค ํ์ ์ ์ฌ๋ฌ๊ฐ ๋ด๊ณ ์๋ ๋ฐฐ์ด์ ๋ณต์ ํ ๋๋ ์ฃผ์ ์ฌํญ์ด ๋ฐ๋ฅธ๋ค.
๊ฐ์ฒด ๋ฐฐ์ด์ ๊ทธ ์์ฒด๋ก๋ ์ฐธ์กฐ ํ์ ์ด๋ฉฐ, ๊ฐ์ง๊ณ ์๋ ์์์ ๊ฐ ์ญ์ ์ฐธ์กฐ ํ์ ์ด๋ค. ์ด์ฒ๋ผ ์ฐธ์กฐ ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ ์ฐธ์กฐ ํ์ ์ ํด๋์ค ์๋ฃํ์ clone ํ์ ๊ฒฝ์ฐ ์ด๋ค ์ผ์ด ์ผ์ด๋๋์ง ๋ณด์.
import java.util.Arrays;
class MyObject{
int id;
String description;
MyObject(int id, String description) {
this.id = id;
this.description = description;
}
}
public class Main {
public static void main(String[] args) {
MyObject[] arrayObj = {
new MyObject(101, "first"),
new MyObject(101, "second"),
new MyObject(101, "third")
};
System.out.println(Arrays.toString(arrayObj)); // [main$1MyObject@251a69d7, main$1MyObject@7344699f, main$1MyObject@6b95977]
MyObject[] arrayObj2; // ๋ณต์ฌํ ๋ฐฐ์ด
arrayObj2 = arrayObj.clone(); // ๋ฐฐ์ด์ ๋ณต์ฌํด๋ ๋ด์ฉ๋ฌผ ๊ฐ์ฒด์ ์ฃผ์๋ ๋๊ฐ๋ค.
System.out.println(Arrays.toString(arrayObj2)); // [main$1MyObject@251a69d7, main$1MyObject@7344699f, main$1MyObject@6b95977]
System.out.println(arrayObj[0].id); // 101
arrayObj2[0].id = 999; // ๋ณต์ฌํ arrayObj2์ ์ฒซ์งธ ๊ฐ์ฒด์ ๋ฉค๋ฒ๋ฅผ ๋ณ๊ฒฝ
// ์๋ณธ๊ณผ ๋ณต์ฌ๋ณธ์ ๊ฐ์ด ๊ฐ๋ค.
System.out.println(arrayObj2[0].id); // 999
System.out.println(arrayObj[0].id); // 999 : arrayObj1 ์ ์ฒซ์งธ ๊ฒ์ฒด์ ๋ฉค๋ฒ๋ ๋ณ๊ฒฝ๋จ
}
}
์ฝ๋์ ์ถ๋ ฅ์ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด, ์ฐธ์กฐ ๊ฐ์ฒด์ธ ๋ฐฐ์ด ์์ฒด๋ ์๋ฒฝํ ๋ณต์ฌ๊ฐ ๋์์ง๋ง, ๋ฐฐ์ด ๋ด์ฉ๋ฌผ ๊ฐ์ฒด๋ ์์ ๋ณต์ฌ๊ฐ ๋์ด ๋ฒ๋ ค ์๋ณธ๊ณผ ๋ฐฐ์ด๋ณธ์ ๋ฐฐ์ด ์์๊ฐ ๋ด๊ณ ์๋ ์ฃผ์๊ฐ์ด ๊ฐ์ ๋ฐ๋ผ๋ณด๊ณ ์๋ ํ ๋ฐ์ดํฐ๊ฐ ๊ฐ๊ฒ ๋์ด๋ฒ๋ ธ๋ค.
๊ทธ๋์ ๋ง์ง๋ง์ ๋ฐฐ์ด ์์์ ํ๋๊ฐ์ ๋ณ๊ฒฝํ๋๋ ์๋ณธ์ ์์๋ ๋ณ๊ฒฝ๋จ์ ๋ณผ ์ ์๋ค.
์ฆ, ๋ฐฐ์ด ๋ด์ฉ๋ฌผ์ ์ฌ์ ํ ๊ฐ์ ๊ฐ์ฒด ์ฃผ์๋ฅผ ๊ฐ๋ฆฌํค๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๋ ๋ณต์ฌ ๋์๋ ์ค ์๊ณ ๋ณต์ฌํ ๊ฐ์ฒด์ ๋ฉค๋ฒ๋ฅผ ๋ณ๊ฒฝํ๋ฉด ๋ณต์ฌ๋ ๋ฉค๋ฒ์ ๊ฐ์ฒด๋ ๋ณ๊ฒฝ๋๋ ๊ผด์ด ๋๋ค.

๋ฐ๋ผ์ ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ๋ณต์ ๋๋ ๋์์ด๋ฉฐ ๋ฐฐ์ด์ ์์ ๋ฐ์ดํฐ์ธ MyObject ํด๋์ค์ Object.clone() ์ ์ฌ์ ์ ํด์ค์ผ๋ก์, ์ง์ for๋ฌธ์ ๋๋ฉฐ ๊ฐ์ฒด ๋ณต์ฌ๋ฅผ ํด์ฃผ์ด์ผ ํ๋ค.
์ฆ, ๋ฐ์ดํฐ๋ฅผ clone ํ๋ ๊ฒ์ ํต์ฌ์, ๋ฐ์ดํฐ๋ฅผ ๋ณต์ฌํ ๋ intํ์ด๋ doubleํ ๊ฐ์ primitive ํ์
์ด ์๋, ํด๋์ค๋ฅผ ๋ณต์ฌํ ์ผ์ด ์์ ๊ฒฝ์ฐ clone() ์ ์ค๋ฒ๋ผ์ด๋ฉ ํ์ฌ์ผ ์๋ฒฝํ ๋ณต์ฌ๊ฐ ํํด์ง๋ค๋ ์ ์ด๋ค.
๋ง์ผ ๋ค๋ฃจ๋ ๋ฐ์ดํฐ์ ํํ๊ฐ ๊ฐ์ฒด์ ๊ฐ์ reference ํ์ ์ผ ๊ฒฝ์ฐ clone ๋ฉ์๋๋ฅผ ์ฌ์ ์ํด์ผ ๋๋ค๋ผ๊ณ ์๊ธฐํ์!
package house;
import java.util.Arrays;
class MyObject implements Cloneable{
int id;
String description;
MyObject(int id, String description) {
this.id = id;
this.description = description;
}
@Override // ๊ณต๋ณ ๋ฐํ ํ์
์ ์ด์ฉํ ์ค๋ฒ๋ผ์ด๋ฉ
public MyObject clone() throws CloneNotSupportedException {
return (MyObject) super.clone();
}
}
public class Test1 {
public static void main(String[] args) {
try {
MyObject[] arrayObj = {
new MyObject(101, "first"),
new MyObject(102, "second"),
new MyObject(103, "third")
};
System.out.println(Arrays.toString(arrayObj)); // [MyObject@251a69d7, MyObject@7344699f, MyObject@6b95977]
MyObject[] arrayObj2 = new MyObject[3];
for (int i = 0; i < arrayObj.length; i++) {
arrayObj2[i] = arrayObj[i].clone();
}
// ๋ฐฐ์ด ๋ด์ฉ๋ฌผ ๊ฐ์ฒด์ @์ฃผ์๊ฐ ๋ฌ๋ผ์ง์ ๋ณผ ์ ์๋ค.
System.out.println(Arrays.toString(arrayObj2)); // [MyObject@1540e19d, MyObject@677327b6, MyObject@14ae5a5]
System.out.println(arrayObj[0].id); // 101
arrayObj2[0].id = 999; // ๋ณต์ฌํ arrayObj2์ ์ฒซ์งธ ๊ฐ์ฒด์ ๋ฉค๋ฒ๋ฅผ ๋ณ๊ฒฝ
// ์๋ณธ๊ณผ ๋ณต์ฌ๋ณธ์ ๊ฐ์ด ๋ค๋ฅด๊ฒ ๋๋ค.
System.out.println(arrayObj2[0].id); // 999
System.out.println(arrayObj[0].id); // 101
} catch (Exception e) {}
}
}
[ ๊ณต๋ณ ๋ฐํ ํ์ ]
๋ณธ๋ ์ค๋ฒ๋ผ์ด๋ฉ์ ๋ถ๋ชจ์ ๋ฉ์๋์ ์๊ทธ๋์ฒ๊ฐ ๊ฐ์์ผ ๊ฐ๋ฅํ๋ค. ์ฆ, ์๊ท๋จผํธ ๊ฐฏ์๋ ๋ฉ์๋ ๋ฐํ ํ์ ์ด ์๋ฒฝํ ์ผ์นํด์ผ ๋๋ค๋ ๋ง์ด๋ค.
JDK 1.5๋ถํฐ '๊ณต๋ณ ๋ฐํ ํ์ (convariant return type)'์ด ์ถ๊ฐ๋์๋๋ฐ, ์ด ๊ธฐ๋ฅ์ ์ค๋ฒ๋ผ์ด๋ฉ ํ ๋ ๋ถ๋ชจ ๋ฉ์๋์ ๋ฐํ ํ์ ์ ์์ ํด๋์ค์ ํ์ ์ผ๋ก ๋ณ๊ฒฝ์ ํ์ฉํ๋ ๊ฒ์ด๋ค.
๊ณต๋ณ ๋ฐํ ํ์ ์ ์ฌ์ฉํ๋ฉด ๋ถ๋ชจ์ ํ์ ์ด ์๋, ์ค์ ๋ฐํ๋๋ ์์ ๊ฐ์ฒด์ ํ์ ์ผ๋ก ๋ฐํํ ์ ์์ด์ ๋ฒ๊ฑฐ๋ก์ด ํ๋ณํ์ด ์ค์ด๋ ๋ค๋ ์ฅ์ ์ด ์๋ค.
# ์ฐธ๊ณ ์๋ฃ
https://www.youtube.com/watch?v=Mc6OaicCZVA
https://www.youtube.com/watch?v=NI6QZy6juc8
์ด ๊ธ์ด ์ข์ผ์ จ๋ค๋ฉด ๊ตฌ๋ & ์ข์์
์ฌ๋ฌ๋ถ์ ๊ตฌ๋
๊ณผ ์ข์์๋
์ ์์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค.