728x90
반응형
Java에서 Map, List, String의 깊은 복사 방법
Java에서 Map, List, String을 깊은 복사하는 방법을 살펴보겠습니다.
1. ArrayList 깊은 복사
방법 1: for 루프 사용 (가장 기본적인 방법)
List<Item> deepCopy = new ArrayList<>();
for (Item item : originalList) {
deepCopy.add(new Item(item.name)); // 개별 객체 복사
}
- 장점: 간단하고 빠름.
- 단점: 코드가 길어질 수 있음.
방법 2: stream() + map() 사용 (람다식 활용)
List<Item> deepCopy = originalList.stream()
.map(item -> new Item(item.name)) // 새로운 객체 생성
.collect(Collectors.toList());
- 장점: 한 줄로 간결하게 작성 가능.
- 단점: stream() 사용으로 가독성이 떨어질 수 있음.
방법 3: clone() 사용 (Cloneable 인터페이스)
class Item implements Cloneable {
String name;
Item(String name) {
this.name = name;
}
@Override
protected Object clone() {
return new Item(this.name); // 새로운 객체 반환
}
}
List<Item> deepCopy = new ArrayList<>();
for (Item item : originalList) {
deepCopy.add((Item) item.clone()); // clone() 사용
}
- 장점: 객체 복사가 필요할 때 유용.
- 단점: Cloneable 인터페이스를 구현해야 하며, clone() 은 예외 처리가 필요할 수 있음.
2. HashMap 깊은 복사
방법 1: for 루프 사용 (기본적인 방법)
Map<Integer, Item> deepCopy = new HashMap<>();
for (Map.Entry<Integer, Item> entry : originalMap.entrySet()) {
deepCopy.put(entry.getKey(), new Item(entry.getValue().name)); // 새로운 객체 복사
}
- 장점: 가장 직관적이고 빠름.
- 단점: 코드가 길어질 수 있음.
방법 2: stream() 사용 (람다식)
Map<Integer, Item> deepCopy = originalMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> new Item(entry.getValue().name) // 새로운 객체 복사
));
- 장점: 간결한 코드.
- 단점: stream() 사용으로 가독성이 떨어질 수 있음.
방법 3: clone() 사용 (Cloneable 인터페이스)
Map<Integer, Item> deepCopy = new HashMap<>();
for (Map.Entry<Integer, Item> entry : originalMap.entrySet()) {
deepCopy.put(entry.getKey(), (Item) entry.getValue().clone()); // clone() 사용
}
- 장점: 객체가 많을 경우 관리하기 용이.
- 단점: Cloneable 구현 필요.
Map<K, List<T>> 깊은 복사 방법
방법 1: for 루프를 사용한 깊은 복사 (기본적인 방법)
Map<Integer, List<Item>> deepCopy = originalMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
.map(item -> new Item(item.name)) // 개별 객체 복사
.collect(Collectors.toList())
));
- 장점: 가장 직관적이고 성능이 좋음.
- 단점: 코드가 조금 길어질 수 있음.
방법 2: stream() + map() 사용 (람다식 활용)
Map<Integer, List<Item>> deepCopy = originalMap.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
.map(item -> new Item(item.name)) // 개별 객체 복사
.collect(Collectors.toList())
));
- 장점: 한 줄로 간결하게 작성 가능.
- 단점: stream() 사용으로 가독성이 떨어질 수 있음.
방법 3: clone() 사용 (Cloneable 인터페이스 활용)
class Item implements Cloneable {
String name;
Item(String name) {
this.name = name;
}
@Override
protected Object clone() {
return new Item(this.name);
}
}
Map<Integer, List<Item>> deepCopy = new HashMap<>();
for (Map.Entry<Integer, List<Item>> entry : originalMap.entrySet()) {
List<Item> copiedList = new ArrayList<>();
for (Item item : entry.getValue()) {
copiedList.add((Item) item.clone()); // clone() 사용
}
deepCopy.put(entry.getKey(), copiedList);
}
- 장점: clone() 을 사용하여 복사할 때 가독성이 높아짐.
- 단점: Cloneable 인터페이스를 구현해야 함.
함수로 깊은 복사는 불가능한가?
답! 가능은 하다.
1) 객체(참조형 데이터)가 없고, 오직 기본형(Primitive Type) 또는 String(불변 객체) 으로 구성된 경우
→ System.arraycopy(), Arrays.copyOf(), HashMap.clone() 만으로도 완전한 깊은 복사 가능 ✅
2) 객체(참조형 데이터)가 포함된 경우
→ 얕은 복사가 되므로 추가적인 객체 복사가 필요 ❌
1. ArrayLIst로 기본 자료형 배열 및 String 배열 깊은 복사
System.arraycopy() 와 Arrays.copyOf() 는 객체 배열이 아닌 기본형 배열 또는 String 배열의 경우 완전한 깊은 복사가 가능하다.
●copyOf (기본형 배열 복사 → 깊은 복사 O)
int[] originalArray = {1, 2, 3, 4, 5};
// 깊은 복사 (값을 완전히 새로 복사)
int[] deepCopy = Arrays.copyOf(originalArray, originalArray.length);
// deepCopy 값을 변경해도 originalArray 에 영향 없음
deepCopy[0] = 99;
System.out.println(Arrays.toString(originalArray)); // [1, 2, 3, 4, 5]
System.out.println(Arrays.toString(deepCopy)); // [99, 2, 3, 4, 5]
- 기본 자료형 배열(int, double, char 등)은 값 자체를 복사하므로 깊은 복사.
- System.arraycopy() 사용해도 같은 결과.
●arraycopy () (String 배열 복사 → 깊은 복사 O)
String[] originalArray = {"A", "B", "C"};
// 깊은 복사 (새로운 배열 생성)
String[] deepCopy = Arrays.copyOf(originalArray, originalArray.length);
// deepCopy 값 변경 (String은 불변 객체이므로 변경해도 원본 영향 없음)
deepCopy[0] = "Z";
System.out.println(Arrays.toString(originalArray)); // [A, B, C]
System.out.println(Arrays.toString(deepCopy)); // [Z, B, C]
- String 은 불변 객체(Immutable Object)이므로 새로운 String 값을 대입해도 원본에 영향이 없음.
2. HashMap.clone() (Key-Value 구조의 깊은 복사)
Key, Value 가 모두 불변 객체(기본형, String) 로만 구성된 경우, clone() 으로 깊은 복사가 가능.
●HashMap.clone() (Key-Value가 String으로만 구성 → 깊은 복사 O)
HashMap<String, String> originalMap = new HashMap<>();
originalMap.put("A", "Apple");
originalMap.put("B", "Banana");
HashMap<String, String> deepCopy = (HashMap<String, String>) originalMap.clone();
// deepCopy 값 변경
deepCopy.put("A", "Avocado");
// 원본은 영향 없음
System.out.println(originalMap.get("A")); // Apple
System.out.println(deepCopy.get("A")); // Avocado
- String 은 불변 객체이므로 clone() 으로도 완전한 깊은 복사가 가능.
정리
☞ 장점, 단점
방법 | ArrayList | HashMap |
for 루프 | 빠르고 직관적 | 코드가 길어짐 |
stream() | 간결한 코드 | stream() 가독성 |
clone() | 객체 복사 용이 | Cloneable 구현 필요 |
☞ 결론
- 가장 간단한 방법: for 루프
- 깔끔한 코드: stream()
- 객체 복사 관리가 필요하면: clone()
- 함수로 깊은 복사가 가능하다, 참조형 데이터(객체)가 포함 되어 있다면 불가능하다.
☞ 추천 방법
- 일반적으로 for 루프 or stream() 사용
- 복잡한 경우 clone() or Serialization 고려
★용도에 맞게 잘 사용해보도록 하자!
728x90
반응형
'프로그래밍 > JAVA' 카테고리의 다른 글
Java 제네릭 와일드카드 사용법 | ?, ? extends, ? super 차이점 한눈에! (1) | 2025.03.04 |
---|---|
Java 제네릭(Generic) 쉽게 이해하기 – 타입 안정성과 코드 재사용성 극대화 (3) | 2025.03.04 |
Java 깊은 복사 vs 얕은 복사 완벽 정리 (+ 예제 코드) (0) | 2025.03.03 |
Java 불변 객체(Immutable Object)란? 불변객체 vs 가변객체 정리 (0) | 2025.03.03 |
객체 지향 프로그래밍(OOP)란? 객체 지향 프로그래밍(OOP) vs 함수형 프로그래밍(FP) 차이점 (1) | 2025.03.03 |
댓글