implementation은 인터페이스 섹션에 설명된 인터페이스를 구현하는 컬렉션을 저장하는 데 사용되는 data object입니다. 이 강의에서는 다음과 같은 종류의 구현을 설명합니다.
java.util.concurrent 패키지의 일부입니다.범용 구현은 다음 표에 요약되어 있습니다.
| Interfaces | Hash table Implementations | Resizable array Implementations | Tree Implementations | Linked list Implementations | Hash table + Linked list Implementations |
|---|---|---|---|---|---|
Set |
HashSet |
TreeSet |
LinkedHashSet |
||
List |
ArrayList |
LinkedList |
|||
Queue |
|||||
Deque |
ArrayDeque |
LinkedList |
|||
Map |
HashMap |
TreeMap |
LinkedHashMap |
표에서 볼 수 있듯이 Java 컬렉션 프레임워크는 Set, List 및 Map 인터페이스의 여러 범용 구현을 제공합니다. 각각의 경우에 하나의 구현(HashSet, ArrayList 및 HashMap)은 확실히 대부분의 애플리케이션에 사용되는 구현이며 다른 모든 항목은 동일합니다. SortedSet 및 SortedMap 인터페이스에는 테이블에 행이 없습니다. 각 인터페이스에는 하나의 구현(TreeSet 및 TreeMap)이 있으며 Set 및 Map 행에 나열됩니다. 두 가지 범용 대기열 구현이 있습니다. LinkedList는 List 구현이기도 하고, PriorityQueue는 표에서 생략되었습니다. 이 두 구현은 매우 다른 의미를 제공합니다. LinkedList는 FIFO 의미를 제공하는 반면 PriorityQueue는 해당 값에 따라 요소의 순서를 지정합니다.
각 범용 구현은 해당 인터페이스에 포함된 모든 선택적 작업을 제공합니다. 모두 null 요소, 키 및 값을 허용합니다. 동기화(synchronized)된 항목은 없습니다(thread-safe). 모두에는 iteration 중에 불법적인 동시 수정을 감지하고 미래의 불확실한 시간(undetermined time)에 임의적이고(arbitrary) 비결정적인(non-deterministic) 동작을 위험에 빠뜨리는 대신 빠르고 깔끔하게 실패하는 fail-fast iterators가 있습니다. 모두 직렬화 가능(Serializable)하며 모두 public clone 메서드을 지원합니다.
이러한 구현이 동기화되지 않았다는 사실은 과거와의 단절을 나타냅니다. 레거시 컬렉션 Vector 및 Hashtable은 동기화됩니다. 동기화가 아무런 이점이 없을 때 컬렉션이 자주 사용되기 때문에 현재 접근 방식을 취했습니다. 이러한 용도에는 단일 스레드(single-threaded) 사용, 읽기 전용(read-only) 사용 및 자체 동기화(own synchronization)를 수행하는 더 큰 데이터 개체의 일부로 사용이 포함됩니다. 일반적으로 사용자가 사용하지 않는 기능에 대해 비용을 지불하도록 하지 않는 것이 좋은 API 설계 방식입니다. 또한 불필요한 동기화로 인해 특정 상황에서 교착 상태(deadlock)가 발생할 수 있습니다.
스레드로부터 안전한(thread-safe) 컬렉션이 필요한 경우 래퍼 구현 섹션에 설명된 동기화 래퍼를 사용하면 모든 컬렉션을 동기화된 컬렉션으로 변환할 수 있습니다. 따라서 동기화는 범용 구현에서는 선택 사항이지만 레거시 구현에서는 필수입니다. 또한 java.util.concurrent 패키지는 Queue를 확장하는 BlockingQueue 인터페이스와 Map을 확장하는 ConcurrentMap 인터페이스의 동시 구현(concurrent implementation)을 제공합니다. 이러한 구현은 단순한 동기화 구현보다 훨씬 높은 동시성을 제공합니다.
원칙적으로(As a rule) 구현이 아닌 인터페이스에 대해 생각해야 합니다. 이것이 바로 이 섹션에 프로그래밍 예제가 없는 이유입니다. 대부분의 경우 구현 선택은 성능에만 영향을 미칩니다. 인터페이스 섹션에서 언급한 대로 선호되는 스타일은 Collection이 생성될 때 구현을 선택하고 새 컬렉션을 해당 인터페이스 유형의 변수에 즉시 할당하는 것입니다(또는 인터페이스 타입의 인수를 기대하는 메서드에 컬렉션을 전달하는 것입니다). 이러한 방식으로 프로그램은 주어진 구현에 추가된 메서드에 종속되지 않으므로 프로그래머는 성능 문제나 동작 세부 사항에 의해 보장되는 경우 언제든지 구현을 자유롭게 변경할 수 있습니다.
다음 섹션에서는 구현에 대해 간략하게 설명합니다. 구현의 성능은 작업 수행의 시간 복잡도에 대한 점근적(asymptotic) 상한을 참조하기 위해 상수 시간(constant-time), 로그(log), 선형(linear), n log(n) 및 quadratic와 같은 단어를 사용하여 설명됩니다. 이 모든 것은 꽤 많은 내용이며, 그것이 무엇을 의미하는지 모른다면 별로 중요하지 않습니다. 더 알고 싶다면 좋은 알고리즘 교과서를 참조하세요. 한 가지 명심해야 할 점은 이러한 종류의 성능 지표에는 한계가 있다는 것입니다. 때로는 명목상 느린 구현이 더 빠를 수도 있습니다. 의심스러울 때는 성능을 측정해 보세요!