자바에서 객체 복사 방법은 무엇인가요?

_____
Q1: 자바에서 객체를 복사하는 방법에는 어떤 것이 있나요?
A1: 자바에서 객체 복사는 주로 다음 세 가지 방법으로 할 수 있습니다.
1. 얕은 복사(Shallow Copy) - 필드 값만 복사하며, 참조형 필드는 주소를 복사합니다.
2. 깊은 복사(Deep Copy) - 모든 참조 객체까지 새로운 객체로 복사합니다.
3. clone() 메서드 사용 - `Cloneable` 인터페이스를 구현하고 `clone()` 메서드를 오버라이드하여 복사합니다.

---

Q2: 얕은 복사란 무엇이고, 어떻게 구현하나요?
A2: 얕은 복사는 객체의 필드 값만 복사하여 새 객체를 만드는 방법입니다. 기본형 필드는 값 자체를 복사하고, 참조형 필드는 객체 주소만 복사하므로 원본과 복사본이 같은 참조 객체를 공유합니다.
구현 방법 예시:
- 생성자를 이용해 필드 복사
- `Object`의 `clone()` 메서드 기본 구현 사용 (가장 기본은 `super.clone()` 호출)

---

Q3: 깊은 복사란 무엇인가요?
A3: 깊은 복사는 객체와 그 객체가 참조하는 모든 객체들을 재귀적으로 새 객체로 복사하는 방법입니다. 이를 통해 복사본은 원본과 완전히 독립된 상태가 됩니다.
직접 구현 시, 각 참조 객체도 복사 생성자나 clone 메서드를 이용해 복사해야 합니다.

---

Q4: clone() 메서드를 사용한 객체 복사 방법은?
A4: `clone()` 메서드는 객체의 얕은 복사를 지원합니다. 사용법은 다음과 같습니다.
1. 클래스에 `Cloneable` 인터페이스 구현 선언
2. `clone()` 메서드를 오버라이드하면서 `super.clone()` 호출
3. 필요시 깊은 복사하려면 참조 필드도 직접 복사 처리
예:
```java
@Override
protected Object clone() throws CloneNotSupportedException {
MyClass cloned = (MyClass) super.clone();
cloned.referenceField = (ReferenceType) referenceField.clone(); // 깊은 복사 예시
return cloned;
}
```

---
Q5: 복사 생성자란 무엇이고 어떻게 사용하나요?
A5: 복사 생성자는 같은 클래스 타입의 객체를 매개변수로 받아 필드 값을 복사해 새 객체를 만드는 생성자입니다.
예:
```java
public MyClass(MyClass other) {
this.field1 = other.field1;
this.referenceField = new ReferenceType(other.referenceField);
}
```

---

Q6: 직렬화를 이용한 객체 복사 방법은?
A6: 객체를 직렬화(바이트 스트림으로 변환) 후 역직렬화하여 완전한 복사본을 얻는 방법입니다. 깊은 복사가 자동으로 되지만, 객체와 참조 객체 모두 `Serializable`을 구현해야 합니다.
예:
```java
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(originalObject);
oos.flush();

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
MyClass copiedObject = (MyClass) ois.readObject();
```

---

Q7: 객체 복사 시 주의할 점은?
A7:
- 얕은 복사는 참조 객체 공유로 원본 데이터가 변경될 수 있으므로 주의
- 깊은 복사는 구현이 복잡하고 성능 저하가 있을 수 있음
- `clone()` 사용 시 `CloneNotSupportedException` 처리 필요
- 직렬화 방법은 성능 비용이 크고, 모든 객체가 `Serializable`이어야 함
- 변경 불가능(Immutable) 객체는 복사 없이 공유해도 안전함

---

Q8: 자바에서 `Object.clone()`과 수동 복사 중 어떤 것이 좋나요?
A8: `clone()` 메서드는 복잡하고 예외 처리, 깊은 복사 구현이 까다로워 유지보수가 어려울 수 있습니다. 따라서 복사 생성자나 팩토리 메서드를 이용한 수동 복사를 권장하는 경우가 많습니다. 직렬화를 통한 복사는 테스트 용도 또는 특수한 경우에 적합합니다.
자바에서 객체 복사는 여러 가지 방법으로 수행할 수 있으며, 각 방법은 특정 상황에 따라 장단점이 있습니다.

객체 복사는 일반적으로 '얕은 복사(Shallow Copy)'와 '깊은 복사(Deep Copy)'로 나눌 수 있습니다.

이 두 가지 방법을 통해 객체를 복사하는 방법을 자세히 살펴보겠습니다.

1. 얕은 복사 (Shallow Copy)얕은 복사는 객체의 필드 값을 복사하지만, 객체가 참조하고 있는 다른 객체는 복사하지 않습니다.

즉, 원본 객체와 복사된 객체가 동일한 참조를 공유하게 됩니다.

얕은 복사는 주로 `clone()` 메서드를 오버라이드하여 구현합니다.

예제 코드```javaclass Person implements Cloneable { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}public class Main { public static void main(String[] args) { try { Person original = new Person("Alice", 30); Person copy = (Person) original.clone(); System.out.println("Original: " + original.name + ", Age: " + original.age); System.out.println("Copy: " + copy.name + ", Age: " + copy.age); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }}```이 예제에서 `Person` 클래스는 `Cloneable` 인터페이스를 구현하고 `clone()` 메서드를 오버라이드하여 얕은 복사를 수행합니다.

`original` 객체를 복사하여 `copy` 객체를 생성합니다.

이 경우, `name`과 `age` 필드는 복사되지만, 만약 `Person` 클래스가 다른 객체를 참조하는 필드를 가졌다면, 그 참조는 공유됩니다.



2. 깊은 복사 (Deep Copy)깊은 복사는 객체와 그 객체가 참조하는 모든 객체를 재귀적으로 복사합니다.

따라서 원본 객체와 복사된 객체는 서로 독립적입니다.

깊은 복사를 구현하는 방법은 여러 가지가 있으며, 일반적으로 다음과 같은 방법을 사용합니다.



2.1. 수동으로 깊은 복사 구현각 필드에 대해 새로운 인스턴스를 생성하여 깊은 복사를 구현할 수 있습니다.

```javaclass Address { String city; public Address(String city) { this.city = city; }}class Person { String name; int age; Address address; public Person(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } public Person deepCopy() { return new Person(this.name, this.age, new Address(this.address.city)); }}public class Main { public static void main(String[] args) { Address address = new Address("New York"); Person original = new Person("Alice", 30, address); Person copy = original.deepCopy(); System.out.println("Original Address: " + original.address.city); System.out.println("Copy Address: " + copy.address.city); // Modify the copy's address copy.address.city = "Los Angeles"; System.out.println("After modification:"); System.out.println("Original Address: " + original.address.city); System.out.println("Copy Address: " + copy.address.city); }}```이 예제에서 `Person` 클래스는 `deepCopy()` 메서드를 통해 깊은 복사를 구현합니다.

`Address` 객체도 새로 생성하여 복사하므로, `original`과 `copy`는 서로 독립적으로 존재합니다.



2.2. 직렬화(Serialization) 사용자바의 직렬화 기능을 사용하여 객체를 깊은 복사할 수도 있습니다.

이 방법은 객체를 바이트 스트림으로 변환한 후 다시 객체로 변환하는 방식입니다.

이 방법을 사용하려면 클래스가 `Serializable` 인터페이스를 구현해야 합니다.

```javaimport java.io.*;class Address implements Serializable { String city; public Address(String city) { this.city = city; }}class Person implements Serializable { String name; int age; Address address; public Person(String name, int age, Address address) { this.name = name; this.age = age; this.address = address; } public Person deepCopy() { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); oos.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (Person) ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); return null; } }}public class Main { public static void main(String[] args) { Address address = new Address("New York"); Person original = new Person("Alice", 30, address); Person copy = original.deepCopy(); System.out.println("Original Address: " + original.address.city); System.out.println("Copy Address: " + copy.address.city); // Modify the copy's address copy.address.city = "Los Angeles"; System.out.println("After modification:"); System.out.println("Original Address: " + original.address.city); System.out.println("Copy Address: " + copy.address.city); }}```이 방법은 객체의 모든 필드가 직렬화 가능할 때 유용하며, 복잡한 객체 구조를 쉽게 복사할 수 있습니다.

그러나 성능이 떨어질 수 있으며, 직렬화가 불가능한 객체가 포함된 경우 예외가 발생할 수 있습니다.

결론자바에서 객체 복사는 얕은 복사와 깊은 복사의 두 가지 방법으로 수행할 수 있습니다.

얕은 복사는 간단하고 빠르지만, 참조하는 객체가 변경되면 원본 객체에도 영향을 미칠 수 있습니다.

깊은 복사는 더 복잡하지만, 객체 간의 독립성을 유지할 수 있습니다.

각 방법의 장단점을 고려하여 상황에 맞는 복사 방법을 선택하는 것이 중요합니다.

작성자: 최윤아 [비회원] | 작성일자: 1년 전 2024-09-05 03:57:01
조회수: 237 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.