๐ ์ด๋ฒ ์๊ฐ์๋ Java์ ๊น์ ๋ณต์ฌ ๊ทธ๋ฆฌ๊ณ ์์ ๋ณต์ฌ์ ๋ํด ์์๋ณด์.
์์ ๋ณต์ฌ์ ๊น์ ๋ณต์ฌ๋ฅผ ์์์ผ ํ๋ ์ด์ ๋ primitive type(int, short..)์ ๊ฒฝ์ฐ๋ ์์ ๋ณต์ฌ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ์ง๋ง,
reference type(Array, object..)์ ๊น์ ๋ณต์ฌ๋ฅผ ์ฌ์ฉํด์ผ ๊ฐ์ฒด์ ์ค์ ๋ฐ์ดํฐ ์ ์ฅ์ด ๊ฐ๋ฅํ๋ค.
- ๊น์ ๋ณต์ฌ: ๋ฉ๋ชจ๋ฆฌ(memory) ์์ ์๋ก์ด ๊ณต๊ฐ์ ํ ๋นํ๊ณ ํด๋น ๋ฉ๋ชจ๋ฆฌ์ ๊ฐ์ ๋ณต์ฌํ๋ ๊ฒ์ ์๋ฏธ
- ์์ ๋ณต์ฌ: ๊ธฐ์กด A ๊ฐ์ฒด๊ฐ ๋ฐ๋ผ๋ณด๊ณ ์๋ ๋ฉ๋ชจ๋ฆฌ(memory)์ ์ฃผ์๊ฐ(reference value)๋ฅผ ๋ณต์ฌํ๋ ๊ฒ์ ์๋ฏธ
๐ค ๊ทธ๋ฌ๋ฉด ํด๋น ํค์๋์ ๋ํด์๋ ์ ๋ฆฌ๋ฅผ ํ์ผ๋ ์์ค ๋ ๋ฒจ์์ 2๊ฐ์ง์ ์ฐจ์ด์ ์ ํ๋ฒ ๋ณด์
package com.test;
class Person {
private String name;
private int age;
public Person() {
}
public Person(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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
// given
Person person = new Person("ํ๊ธธ๋", 26);
Person copyPerson = person;
// when
copyPerson.setName("๊น์๋ฏผ");
copyPerson.setAge(26);
// then
System.out.println(person); // Person{name='๊น์๋ฏผ', age=26}
System.out.println(copyPerson); // Person{name='๊น์๋ฏผ', age=26}
}
}
Java ํ๋ก๊ทธ๋๋ฐ์ ํ๋ค๋ณด๋ฉด ๋ฐฐ์ด์ด๋, ์ปฌ๋ ์ (List, Set..)์ ๋ณต์ฌํ ์ผ์ด ์์ฃผ ๋ฐ์ํ๋๋ฐ,
์์ ๋ณต์ฌ, ๊น์ ๋ณต์ฌ์ ๋ํ ๊ฐ๋ ์์ด ๋ง๊ตฌ์ก์ด๋ก ๋ณต์ฌํ์ง๋ง์... ์ด์๋ก ์ด์ด์ง์๋ ์๋ค.
์์ ๋ณต์ฌ
๋์ฃผ์์ ์ํ ์ฐธ์กฐ
,call by reference
์ ์ ์ฌํ ๊ฐ๋ ์ ๊ฐ๋๋ค๋ณต์ฌ
ํ๋ ค๋์๋ณธ ๊ฐ์ฒด
์ ๋ํด์์๋ก์ด ๋จ์ผ ๊ฐ์ฒด
๋ฅผ ๋ง๋ค๊ณ์๋ณธ ๊ฐ์ฒด ์ฐธ์กฐ
์ ์์๋ฅผ ๋ณด๋ฉด ํ์ฌ name, age๋ฅผ ์ธ์คํด์ค ๋ณ์๋ก ๊ฐ์ง๊ณ ์๋ Person ํด๋์ค๊ฐ ์กด์ฌํ๋ค.
main ํจ์์์ ์์ฑ์๋ฅผ ํตํด ์ ๊ท Person ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ ํ์ copyPerson ๋ณ์์ ์์ ๋ณต์ฌ๋ฅผ ํ์๋ค.
๊ธฐ๋ํ ๋ถ๋ถ์ person ๋ณ์๋ 'ํ๊ธธ๋', 26 ์ด๋ผ๋ ๊ฐ์ด ๋์ค๊ณ , copyPerson ๋ณ์๋ '๊น์๋ฏผ', '26'์ด ๋์ฌ ๊ฒ์ด๋ผ ์์ํ์ง๋ง
์ค์ ๊ฒฐ๊ณผ์์๋ 2๊ฐ์ ๊ฐ์ฒด ๋ชจ๋ ์๋์ ๊ฐ์ด '๊น์๋ฏผ', 26์ด๋ผ๋ ๊ฐ์ ์๋ต
ํ๊ฒ ๋๋ค.
// ์ฝ์ ๊ฒฐ๊ณผ
Person{name='๊น์๋ฏผ', age=26}
Person{name='๊น์๋ฏผ', age=26}
Process finished with exit code 0
โ ์ 2๊ฐ์ ๊ฐ์ฒด๊ฐ ๋์ผํ ๊ฐ์ ๋ฐํํ๋ ๊ฒ์ผ๊น?
2๊ฐ์ ๊ฐ์ฒด๊ฐ ๋์ผํ ๊ฐ์ ๋ฐํํ ์ด์ ๋ person ๋ณ์์ ๊ฐ์ฒด ์ฐธ์กฐ ๊ฐ์ copyPerson ๋ณ์์ ์์ ๋ณต์ฌ ํ์๊ธฐ ๋๋ฌธ์ด๋ค.
์๋ง ์ค์ ๋ฉ๋ชจ๋ฆฌ ๊ตฌ์กฐ ์์์๋ ๋ค์๊ณผ ๊ฐ์ ๊ทธ๋ฆผ์ผ๋ก ์์ฑ์ด ๋ ๊ฒ ์ด๋ค. (๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์ ๋ฒ์ง ์ฐธ์กฐ)
๐ค ์ ๊ตณ์ด ์์ ๋ณต์ฌ๋ฅผ ํด์ผ ํ ๊น? ๊ทธ๋ฆฌ๊ณ ์ด๋ ํ ๊ฒฝ์ฐ์ ์ฃผ๋ก ์ฌ์ฉํ ๊น?
๋ง์ฝ ๊ฐ์ฒด์ ์ฃผ์๊ฐ ๋ณต์ฌ๊ฐ ์๋ ์ค์ ๊ฐ์ ๋ณต์ฌํ๊ณ ์ ํ๋ค๋ฉด ๊น์ ๋ณต์ฌ(deep copy)๋ฅผ ์ํํด์ผ ํ๋ค.
๋ค์์ ๊น์ ๋ณต์ฌ์ ๋ํด ์์๋ณธ๋ค.
๊น์ ๋ณต์ฌ(deep copy)๋ ๊ฐ์ฒด์ ์ฃผ์๊ฐ์ด ์๋ ์๋ก์ด ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ฐ์ ๋ณต์ฌํ์ฌ ์ ์ฅํ๋ ๊ฒ์ ์๋ฏธํ๋ค.
๊น์ ๋ณต์ฌ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋ํ์ ์ผ๋ก 3๊ฐ์ง ์กด์ฌํ๋ค.
๋ณต์ฌ ์์ฑ์
๋๋๋ณต์ฌ ํฉํ ๋ฆฌ
์ด์ฉํ์ฌ ๋ณต์ฌ์ง์ ๊ฐ์ฒด ์์ฑ
ํ๋ณต์ฌ
Clonable ์ธํฐํ์ด์ค
๊ตฌํํ์ฌclone() ํจ์ ์ค๋ฒ๋ผ์ด๋ฉ
ํ ๋ณต์ฌ
package com.test;
class CopyObject {
private String name;
private int age;
/* NoArgsConstructor */
public CopyObject() {
}
/* ๋ณต์ฌ ์์ฑ์ */
public CopyObject(CopyObject copyObject) {
this.name = copyObject.getName();
this.age = copyObject.getAge();
}
/* ๋ณต์ฌ ํฉํ ๋ฆฌ */
public static CopyObject copy(CopyObject copyObject) {
CopyObject copy = new CopyObject(copyObject.getName(), copyObject.getAge()); // ๊ธฐ๋ณธ ์์ฑ์ ํธ์ถ
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;
}
}
public class Test {
public static void main(String[] args) {
CopyObject original = new CopyObject("YM", 30); // ์๋ณธ
CopyObject copyConstructor = new CopyObject(original); // ์์ฑ์ ๋ณต์ฌ
CopyObject copyFactory = CopyObject.copy(original); // ํฉํ ๋ฆฌ ๋ณต์ฌ
System.out.println("[๋ณ๊ฒฝ ์ ] original = " + original.getName()); // [๋ณ๊ฒฝ ์ ] original = YM
System.out.println("[๋ณ๊ฒฝ ์ ] copyConstructor = " + copyConstructor.getName()); // [๋ณ๊ฒฝ ์ ] copyConstructor = YM
System.out.println("[๋ณ๊ฒฝ ์ ] copyFactory = " + copyFactory.getName() + "\n"); // [๋ณ๊ฒฝ ์ ] copyFactory = YM
copyConstructor.setName("KIM");
copyFactory.setName("JUNE");
System.out.println("[๋ณ๊ฒฝ ํ] original = " + original.getName()); // [๋ณ๊ฒฝ ํ] original = YM
System.out.println("[๋ณ๊ฒฝ ํ] copyConstructor = " + copyConstructor.getName()); // [๋ณ๊ฒฝ ํ] copyConstructor = KIM
System.out.println("[๋ณ๊ฒฝ ํ] copyFactory = " + copyFactory.getName()); // [๋ณ๊ฒฝ ํ] copyFactory = JUNE
}
}
// ์ฝ์ ๊ฒฐ๊ณผ
[๋ณ๊ฒฝ ์ ] original = YM
[๋ณ๊ฒฝ ์ ] copyConstructor = YM
[๋ณ๊ฒฝ ์ ] copyFactory = YM
[๋ณ๊ฒฝ ํ] original = YM
[๋ณ๊ฒฝ ํ] copyConstructor = KIM
[๋ณ๊ฒฝ ํ] copyFactory = JUNE
๋ณต์ฌ ์์ฑ์
๊ทธ๋ฆฌ๊ณ๋ณต์ฌ ํฉํ ๋ฆฌ
๋๊น์ ๋ณต์ฌ
public class Test {
public static void main(String[] args) {
CopyObject c1 = new CopyObject("AAA", 40);
CopyObject c2 = new CopyObject(c1.getName(), c1.getAge());
c2.setName("๋ณ๊ฒฝํ์ง๋กฑ");
c2.setAge(3333);
//System.out.println(c1);
//System.out.println(c2);
System.out.println(c1.getName());
System.out.println(c2.getName());
}
}
// ์ฝ์ ๊ฒฐ๊ณผ
//com.test.CopyObject@3796751b
//com.test.CopyObject@67b64c45
AAA
๋ณ๊ฒฝํ์ง๋กฑ
- ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๊ฐ ์๋ก ๋ค๋ฅด๋ฉฐ, ๋ฐ์ดํฐ๋ ๋ค๋ฆ
// Object.java
// Java Doc... ์ฃผ์ ์ค๋ต
@HotSpotIntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;
// Cloneable.java
// Java Doc... ์ฃผ์ ์ค๋ต
public interface Cloneable {
}
clone์ Object์ ์ ์๋์ด ์๋ค, ์ฐ๊ณ ์ถ์ผ๋ฉด 'Cloneable ์ธํฐํ์ด์ค ๊ตฌํ' ํ ์ฐ๋ผ๊ณ ํ๋ค? ๐ค
๊ทผ๋ฐ Cloneable ์ธํฐํ์ด์ค๋ฅผ ์ด์ด๋ณด๋ฉด ๋ณธ๋ฌธ์ด ๋น์ด์๋ ์ธํฐํ์ด์ค์ด๋ค(์ค์ ๋ก๋ ๋ง์ปค ์ธํฐํ์ด์ค)
์ฐธ๊ณ : Java: Cloneable์ ๋ํ ๊ณ ์ฐฐ
์ค์ Object ํด๋์ค
์ ๋ค์ด๊ฐ๋ณด๋ฉด ์์ ๊ฐ์ด clone()
๋ฉ์๋๊ฐ protected native
๋ก ์ ์ธ๋์ด ์๋๊ฑธ ํ์ธ ํ ์ ์๋ค.
clone()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ ค๋ฉด Cloneable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํ
ํด์ผ ํ๋ฉฐ, ๋ง์ฝ ๊ตฌํํ์ง ์์ผ๋ฉด CloneNotSupportedException
์ด ๋ฐ์ํ๊ฒ ๋๋ค.
native ํค์๋?
native ํค์๋
๋ ์๋ฐ๊ฐ ์๋ ์ธ์ด
(C, C++)๋ก ๊ตฌํ ํ ์๋ฐ์์ ์ฌ์ฉํ๋ ค๊ณ ํ ๋ ์ด์ฉํ๋ ํค์๋
์ด๋ค.
์๋ฐ๋ก ๊ตฌํํ๊ธฐ ๊น๋ค๋ก์ด ๊ฒ์ ๋ค๋ฅธ ์ธ์ด๋ก ๊ตฌํ ํ ์๋ฐ์์ ์ฌ์ฉํ๋ค. ๊ตฌํํ ๋ JNI(Java Native Interface)๋ฅผ ์ฌ์ฉํ๋ค.
์ค์ ๋ก Cloneable์ ๊ตฌํํ๋์ง ํ๋จํ๋ ๋ถ๋ถ์ jvm.cpp ์์ค ์์์ ํ์ธ์ด ๊ฐ๋ฅํ๋ค๊ณ ํ๋ค.
package com.test;
class CloneableObject implements Cloneable {
private String name; // ์ด๋ฆ
private int age; // ๋์ด
// Constructor
public CloneableObject(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;
}
// Object ํด๋์ค์ clone ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ
@Override
public CloneableObject clone() {
try {
return (CloneableObject) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
public class Clone {
public static void main(String[] args) {
// ์ ๊ท ๊ฐ์ฒด ์์ฑ
CloneableObject cloneableObject1 = new CloneableObject("KKK", 13);
// ๋ค๋ฅธ ๊ฐ์ฒด์ ๊น์ ๋ณต์ฌ(Deep Copy ์ํ)
CloneableObject cloneableObject2 = cloneableObject1.clone();
// ๊ฒฐ๊ณผ ์ถ๋ ฅ
System.out.println(cloneableObject1);
System.out.println(cloneableObject2);
System.out.println(cloneableObject1.hashCode());
System.out.println(cloneableObject2.hashCode());
System.out.println(cloneableObject1.getName());
System.out.println(cloneableObject2.getName());
}
}
๋ณต์ฌ๋ฅผ ํ๊ณ ์ ํ๋ Obj(CloneableObject)์์ Cloneable ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ณ Object.clone() ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ๋ค.
ํ์ ํด๋น ๊ฐ์ฒด์ clone() ๋ฉ์๋๋ฅผ ์คํํ๊ธฐ ๋๋ฉด ์๋์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ์ด ๋๋ค.
// ์ถ๋ ฅ ๊ฒฐ๊ณผ
cloneableObject1 => com.test.CloneableObject@7e0ea639
cloneableObject2 => com.test.CloneableObject@3d24753a
cloneableObject1.hashCode() => 2114889273
cloneableObject2.hashCode() => 1025799482
cloneableObject1.getName => KKK
cloneableObject2.getName() => KKK