본문 바로가기
Everyday Study

2024.07.19 (금) { 얕은&깊은복사 , 컬렉션구현방식, sublist - view (부분집합) }

by xogns93 2024. 7. 19.

Java의 컬렉션 프레임워크에 대한 설명

큐(Queue) 인터페이스컬렉션(Collection) 인터페이스를 상속받고, 컬렉션(Collection) 인터페이스이터러블(Iterable) 인터페이스를 상속받습니다. 이터러블(Iterable) 인터페이스에는 이터레이터(Iterator) 인터페이스가 정의되어 있습니다.


얕은 복사 (Shallow Copy)

얕은 복사는 객체의 최상위 수준만 복사하며, 중첩된 객체들은 원본 객체와 같은 참조를 공유하게 됩니다. 즉, 객체의 직접적인 속성만 복사되고, 그 속성이 참조하는 다른 객체들은 원본 객체와 동일한 참조를 가집니다.

특징:

  • 최상위 객체의 속성만 복사
  • 중첩된 객체는 동일한 참조를 공유
  • 메모리 사용량 적음
  • 원본 객체의 중첩된 객체를 수정하면 복사된 객체에도 영향을 미침

 

깊은 복사 (Deep Copy)

깊은 복사는 객체의 모든 수준을 재귀적으로 복사하여, 원본 객체와 완전히 독립적인 객체를 생성합니다. 즉, 원본 객체와 복사된 객체는 중첩된 객체까지 모두 별도의 참조를 가집니다.

특징:

  • 객체의 모든 수준을 재귀적으로 복사
  • 중첩된 객체도 새로 생성
  • 메모리 사용량 많음
  • 원본 객체와 복사된 객체는 완전히 독립적

 

 

요약

  • 얕은 복사 (Shallow Copy): 객체의 최상위 수준만 복사하며, 중첩된 객체들은 원본 객체와 같은 참조를 공유합니다.
  • 깊은 복사 (Deep Copy): 객체의 모든 수준을 재귀적으로 복사하여, 원본 객체와 독립적인 객체를 생성합니다.

얕은 복사는 메모리 사용이 적고 속도가 빠르지만, 원본 객체와 복사된 객체 간의 의도치 않은 상호 작용이 발생할 수 있습니다. 깊은 복사는 메모리 사용이 많고 속도가 느릴 수 있지만, 원본 객체와 복사된 객체가 완전히 독립적입니다. 이 두 가지 복사 방식의 차이를 이해하고 상황에 맞게 적절히 사용하는 것이 중요합니다.

 


Java 컬렉션(collection)의 구현 방식(Representation)

 

  1. ArrayList:
    • 구현 방식: 동적 배열
    • 특징:
      • 요소에 대한 인덱스 접근이 빠름 (O(1)).
      • 배열의 크기를 동적으로 조절하며, 요소를 추가하거나 제거할 때는 O(n)의 시간이 소요될 수 있음.
  2. LinkedList:
    • 구현 방식: 이중 연결 리스트 (Doubly Linked List)
    • 특징:
      • 요소의 추가 및 제거가 빠름 (O(1)).
      • 요소에 대한 인덱스 접근이 느림 (O(n)).
  3. HashSet:
    • 구현 방식: 해시 테이블 (Hash Table)
    • 특징:
      • 요소의 중복을 허용하지 않음.
      • 요소의 추가, 제거, 검색이 평균적으로 빠름 (O(1)).
      • 요소의 순서가 보장되지 않음.
  4. TreeSet:
    • 구현 방식: 레드-블랙 트리 (Red-Black Tree)
    • 특징:
      • 요소의 중복을 허용하지 않음.
      • 요소가 항상 정렬된 상태로 유지됨.
      • 요소의 추가, 제거, 검색이 O(log n)의 시간이 소요됨.
  5. HashMap:
    • 구현 방식: 해시 테이블 (Hash Table)
    • 특징:
      • 키-값 쌍으로 저장.
      • 키의 중복을 허용하지 않음.
      • 요소의 추가, 제거, 검색이 평균적으로 빠름 (O(1)).
      • 키와 값의 순서가 보장되지 않음.
  6. TreeMap:
    • 구현 방식: 레드-블랙 트리 (Red-Black Tree)
    • 특징:
      • 키-값 쌍으로 저장.
      • 키의 중복을 허용하지 않음.
      • 요소가 항상 키의 자연 순서로 정렬됨.
      • 요소의 추가, 제거, 검색이 O(log n)의 시간이 소요됨.

sublist - view (부분집합)

 

서브리스트(sublist)는 주어진 리스트(List)의 특정 부분집합을 뷰(View) 형태로 제공하는 기능입니다. Java에서는 List 인터페이스의 subList 메서드를 사용하여 리스트의 특정 부분을 서브리스트로 얻을 수 있습니다. 이 서브리스트는 원본 리스트와 연결된 뷰(View)로 동작하므로, 서브리스트에 대한 변경은 원본 리스트에 영향을 미치고, 원본 리스트에 대한 변경도 서브리스트에 영향을 미칩니다.

 

다음은 Java에서 subList 메서드를 사용하여 서브리스트를 생성하고 사용하는 예시입니다:

import java.util.ArrayList;
import java.util.List;

public class SublistExample {
    public static void main(String[] args) {
        // 원본 리스트 생성
        List<String> originalList = new ArrayList<>();
        originalList.add("Apple");
        originalList.add("Banana");
        originalList.add("Cherry");
        originalList.add("Date");
        originalList.add("Elderberry");

        // 서브리스트 생성 (index 1부터 3까지, 3은 포함되지 않음)
        List<String> subList = originalList.subList(1, 3);

        // 서브리스트 출력
        System.out.println("Sublist: " + subList); // 출력: [Banana, Cherry]

        // 서브리스트 수정
        subList.set(0, "Blueberry");
        System.out.println("Modified Sublist: " + subList); // 출력: [Blueberry, Cherry]

        // 원본 리스트도 변경됨
        System.out.println("Modified Original List: " + originalList); // 출력: [Apple, Blueberry, Cherry, Date, Elderberry]

        // 원본 리스트 수정
        originalList.set(2, "Cantaloupe");
        System.out.println("Modified Sublist after original list change: " + subList); // 출력: [Blueberry, Cantaloupe]
    }
}

중요한 점들

  1. 연결된 뷰(View):
    • subList로 얻은 서브리스트는 원본 리스트의 부분집합에 대한 뷰입니다.
    • 서브리스트에 대한 변경은 원본 리스트에 반영되며, 그 반대도 마찬가지입니다.
  2. 인덱스 범위:
    • subList(int fromIndex, int toIndex) 메서드는 fromIndex부터 toIndex 이전까지의 요소들을 포함합니다.
    • fromIndex는 포함되고, toIndex는 포함되지 않습니다.
    • 위의 예시처럼 List<String> subList = originalList.subList(1, 3); 이면 index 1부터 3까지, 3은 포함되지 않음!
  3. 동시성 문제:
    • 원본 리스트가 서브리스트와 연결된 상태에서 구조적으로 변경되면 (예: 요소 추가/삭제), 서브리스트의 동작은 정의되지 않습니다. 이는 ConcurrentModificationException을 초래할 수 있습니다.
  4. 사용 사례:
    • 큰 리스트의 일부만 처리하고자 할 때 유용합니다.
    • 부분집합을 필요한 범위로 잘라서 작업할 때 사용됩니다.

요약

  • 서브리스트(sublist): 주어진 리스트의 특정 부분을 뷰 형태로 제공.
  • subList 메서드: List 인터페이스의 subList(int fromIndex, int toIndex) 메서드를 사용하여 생성.
  • 뷰(View) 특성: 서브리스트는 원본 리스트와 연결된 뷰로 동작하므로, 한쪽의 변경이 다른 쪽에 영향을 미침.
  • 주의점: 원본 리스트의 구조적 변경이 동시성 문제를 일으킬 수 있음.

서브리스트는 리스트의 특정 부분을 효율적으로 관리하고 작업할 수 있는 유용한 도구입니다. 이를 통해 메모리 사용량을 줄이고, 불필요한 복사를 피할 수 있습니다.