📌 HashSet의 구현 원칙은 무엇인가?
HashSet은 자바의 Set 인터페이스를 구현한 자료 구조로, 중복을 허용하지 않는 요소들의 집합을 저장하는 데 사용한다.
[ 해시 함수 사용 ]
- HashSet은 해시 함수를 사용하여 요소를 저장한다.
- 해시 함수는 요소의 해시 코드를 계산하는 역할을 한다.
- HashSet은 각 요소의 해시 코드를 기반으로 내부 배열에서 요소를 저장하고 검색한다.
[ 동등성 비교 ]
- HashSet은 동일한 해시 코드를 가진 요소를 처리하기 위해 동등성 비교(equality comparison)를 수행한다.
- 동등성 비교는 equals() 메서드를 사용하여 요소 간의 동등성을 확인한다.
- 동등한 요소는 HashSet 내에서 중복을 허용하지 않기 때문에 저장되지 않는다.
[ 해시 충돌 해결 ]
- 해시 함수는 일반적으로 요소의 공간이 무한하지 않기 때문에 서로 다른 요소가 동일한 해시 코드를 가질 수 있다.(해시 충돌, hash collision)
- HashSet은 충돌을 해결하기 위해 개방 주소법(open addressing) 또는 연결리스트(chaining)를 사용한다.
- 개방 주소법: 동일한 버킷에 새로운 요소를 저장할 다른 위치를 찾는 방법.
- 연결 리스트: 동일한 버킷에 속하는 모든 요소들을 연결 리스트로 관리하여 해시 충돌 해결.
[ 순서 보장 X ]
- HashSet은 요소들의 순서를 보장하지 않는다.
- 순서를 보장해야 하는 경우에는 LinkedHashSet을 사용해야 한다.
[ 동기화 X ]
- HashSet은 기본적으로 스레드 간의 안전성을 보장하지 않는다.
- 동기화가 필요한 경우에는 ConcurrentHashMap을 사용해야 한다.
HashSet은 요소의 삽입, 삭제, 검색 작업을 평균적으로 O(1)의 시간 복잡도로 처리할 수 있다.
중복을 허용하지 않는 요소의 집합을 저장하고자 할 때 매우 유용한 자료 구조이다.
📌 ArrayList와 LinkedList의 차이점은 무엇인가?
ArrayList와 LinkedList는 모두 자바에서 제공되는 List 인터페이스의 구현체이다.
두 자료구조는 내부적인 구현 방식과 특징에서 차이가 있다.
[ ArrayList ]
- 내부적으로 배열(Array)로 구현되어 있다.
- 인덱스를 기반으로 한 빠른 임의 접근(random access)이 가능하다.
- 요소의 삽입과 삭제는 배열의 재할당과 복사가 필요할 수 있으므로 비효율적일 수 있다.
- 요소의 추가와 삭제가 리스트의 끝 부분에서 주로 발생하는 경우에는 성능이 좋다.
- 데이터의 크기가 동적으로 변하지 않고, 잦은 검색 및 임의 접근이 필요한 경우에 적합하다.
[ LinkedList ]
- 내부적으로 노드(Node)의 연결 리스트로 구현되어 있다.
- 인덱스를 기반으로 한 접근은 비효율적이며, 요소를 차례대로 탐색해야 한다.
- 해당 노드의 연결만 수정하면 되므로 요소의 삽입과 삭제가 빠르다.
- 요소의 추가와 삭제가 리스트의 중간에서 주로 발생하는 경우에 성능이 좋다.
- 데이터의 크기가 동적으로 변하고, 삽입과 삭제가 빈번하게 발생하는 경우에 적합하다.
ArrayList는 배열 기반으로 빠른 임의 접근이 가능하며, 크기 변화가 적은 경우에 유리하다.
LinkedList는 연결 리스트 기반으로 요소의 삽입과 삭제가 빠르며, 크기 변화가 많은 경우에 유리하다.
📌 Array에서 List로 전환하려면 어떻게 해야 하는가?
[ Arrays.asList() ]
- Arrays 클래스의 asList() 메서드를 사용하여 Array를 List로 변환할 수 있다.
- 고정 크기의 리스트를 생성하며, 리스트의 크기를 변경할 수 없다.
- 배열의 요소를 직접 수정하면 리스트의 요소도 변경된다.
String[] array = {"apple", "banana", "orange"};
List<String> list = Arrays.asList(array);
[ ArrayList의 생성자 또는 addAll() ]
- ArrayList 클래스의 생성자 또는 addAll() 메서드를 사용하여 Array를 List로 변환할 수 있다.
- 가변 크기의 리스트를 생성하며, 리스트의 크기를 동적으로 변경할 수 있다.
String[] array = {"apple", "banana", "orange"};
List<String> list = new ArrayList<>(Arrays.asList(array));
// 또는
List<String> list = new ArrayList<>();
Collections.addAll(list, array);
[ Stream 사용 ]
- 자바 8 이상에서는 Stream을 사용하여 Array를 List로 변환할 수 있다.
- 가변 크기의 리스트를 생성하며, 리스트의 크기를 동적으로 변경할 수 있다.
String[] array = {"apple", "banana", "orange"};
List<String> list = Arrays.stream(array).collect(Collectors.toList());
📌 ArrayList와 Vector의 차이점은 무엇인가?
ArrayList와 Vector는 둘 다 동적 배열(Dynamic Array)를 구현한 자료 구조이다.
그러나 두 가지 주요한 차이점이 있다.
[ 동기화(Synchronization) ]
- ArrayList는 여러 스레드가 동시에 접근할 때 동기화를 보장하지 않는다.
- Vector는 여러 스레드가 동시에 접근할 때 동기화를 보장한다.
[ 성능 ]
- ArrayList는 동기화를 제공하지 않기 때문에 동기화 오버헤드가 없어 일반적으로 Vector 보다 더 빠르다.
- Vector는 각 메서드에 대한 동기화를 수행하기 때문에 동기화 오버헤드로 인해 ArrayList보다 성능이 좀 더 낮을 수 있다.
단일 스레드 환경에서는 ArrayList가 성능면에서 더 좋은 선택일 수 있다. 하지만 멀티스레드 환경이거나 동기화가 필요한 경우에는 Vector를 사용하여 스레드 안전성을 보장할 수 있다.
자바 1.5부터는 동기화를 위해 Vector 대신 동기화된 컬렉션인 Collections.synchronizedList() 메서드를 사용할 수 있으며, 이는 ArrayList와 유사한 성능을 제공한다.
📌 Array와 ArrayList의 차이점은 무엇인가?
[ 크기 조정 ]
Array는 한 번 생성되면 크기를 변경할 수 없지만 ArrayList는 동적으로 크기를 조정할 수 있다.
[ 타입 ]
Array는 동일한 타입의 요소만 저장할 수 있지만 ArrayList는 제네릭을 사용하여 여러 타입의 요소를 저장할 수 있다.
[ 메모리 할당 ]
Array는 요소를 연속적으로 메모리에 할당하는 반면 ArrayList는 내부적으로 배열을 사용하여 요소를 저장하긴 하지만 필요에 따라 크기를 조정하고 새로운 배열에 요소를 복사한다.
[ 속도 ]
Array는 크기가 고정되어 있으므로 요소에 직접 접근하기 때문에 일반적으로 빠르다.
ArrayList는 크기 조정과 요소의 이동이 필요할 수 있으므로 속도가 상대적으로 느릴 수 있다.
[ 기능 ]
Array는 기본적인 배열 기능만을 제공한다.
ArrayList는 Collection 인터페이스를 구현하므로 추가적인 기능과 메서드를 제공한다.(추가, 삭제, 검색, 정렬 등)
크기가 고정되어 있고 단순한 요소 저장 구조를 사용해야 한다면 Array, 동적 크기 조정과 다양한 기능을 활용해야 하거나 제네릭 타입을 사용해야 한다면 ArrayList가 더 적합하다.
📌 Queue에서 poll() 과 remove()의 차이는 무엇인가?
[ poll() ]
- Queue에서 요소를 가져온다.
- Queue가 비어있는 경우 null을 반환한다.
[ remove() ]
- Queue에서 요소를 제거하고, 제거된 요소를 반환한다.
- Queue가 비어있는 경우 NoSuchElementException 예외가 발생한다.
요소의 유무를 사전에 확인하고 예외 처리를 직접 처리하려는 경우에는 remove(), 반면 요소가 없을 때 null 값을 반환하고 예외 처리를 자동으로 처리하려는 경우에는 poll()을 사용할 수 있다.
📌 Thread-Safe한 컬렉션 클래스들은 무엇이 있는가?
[ ConcurrentHashMap ]
- 멀티 스레드 환경에서 안전하게 사용할 수 있는 구현체이다.
- 내부적으로 세분화된 락 분할(lock striping)을 사용하여 동시성을 지원한다.
[ CopyOnWriteArrayList ]
- 읽기 작업이 많이 발생하고 쓰기 작업이 적은 경우에 유용한 Thread-Safe 한 동적 배열이다.
- 쓰기 작업 시에는 내부 배열을 복사하므로 별도의 동기화가 필요하지 않는다.
[ ConcurrentLinkedQueue ]
- 멀티 스레드 환경에서 안전하게 사용할 수 있는 비차단(non-blocking) 큐 구현체이다.
- 여러 스레드에서 요소를 추가하거나 제거할 수 있다.
[ ConcurrentSkipListMap, ConcurrentSkipListSet ]
- Thread-Safe 한 스킵 리스트 구현체이다.
- 키-값을 저장하는 Map과 유니크한 요소를 저장하는 Set으로 사용할 수 있다.
[ BlockingQueue 인터페이스를 구현한 클래스들 ]
- 스레드 간의 작업을 동기화하는데 사용되는 블로킹 큐
- LinkedBlockingQueue, ArrayBlockingQueue, SynchronousQueue 등이 있다.
이 외에도 java.util.concurrent 패키지에는 다양한 Thread-Safe 컬렉션 클래스들이 있다.
📌 Iterator란 무엇인가?
Iterator는 자바에서 컬렉션 객체의 요소를 순회하고, 요소에 접근하기 위한 인터페이스이다.
Iterator는 컬렉션의 내부 구조와는 상관없이 요소를 순차적으로 접근할 수 있는 표준화된 방법을 제공한다.
[ Iterator의 주요 메서드 ]
- hasNext()
- 다음에 요소가 존재하는지의 여부를 확인하는 메서드.
- 요소가 있을 경우 true, 없을 경우 false를 반환한다.
- next()
- 다음 요소를 반환하는 메서드.
- hasNext() 메서드를 호출하여 다음 요소가 있는지 확인한 후, next()를 호출하여 실제 요소를 가져온다.
- remove()
- 현재 가리키고 있는 요소를 삭제하는 메서드.
- 선택적으로 구현할 수 있다.
Iterator를 사용하면 컬렉션 객체의 내부 구조를 알 필요 없이 요소에 접근할 수 있으며, 요소를 순차적으로 처리할 수 있다.
📌 Iterator의 사용 목적은 무엇인가?
[ 요소 순회 ]
- Iterator를 통해 컬렉션의 요소를 순차적으로 방문하면서 처리 작업을 수행할 수 있다.
[ 컬렉션의 내부 구조에 대한 독립성 ]
- Iterator를 사용하면 컬렉션의 내부 구조에 상관없이 요소에 접근할 수 있다.
[ 안전한 요소 수정 및 삭제 ]
- Iterator를 사용하면 컬렉션의 요소를 안전하게 수정하거나 삭제할 수 있다.
- Iterator는 내부적으로 컬렉션의 상태를 추적하고, 컬렉션의 구조적 변경을 허용하지 않으면서 요소를 삭제할 수 있는 메서드`remove()` 를 제공한다.
[ 단방향 순회 ]
- Iterator는 요소를 순차적으로 순회하며, 한 번에 하나의 요소에 접근할 수 있다.
- 순회 방향을 변경하거나 역방향으로는 이동할 수 없다.
📌 Iterator와 ListIterator의 차이는 무엇인가?
[ 방향 ]
- Iterator는 단방향 순회를 지원하며, 순차적으로 요소에 접근한다.
- ListIterator는 양방향 순회를 지원하며, 순차적으로 앞뒤로 이동하면서 요소에 접근한다.
[ 요소 수정 ]
- Iterator는 요소를 읽는 것만 가능하며, 요소의 수정은 불가능하다.
- ListIterator는 요소의 읽기와 수정이 모두 가능하다.
- set() 메서드를 사용하여 현재 요소를 수정할 수 있다.
[ 요소 삽입 및 삭제 ]
- Iterator는 요소를 순회하면서 삭제할 수 있지만, 요소를 추가하거나 삽입하는 기능은 제공하지 않는다.
- ListIterator는 요소의 추가, 삭제 모두 지원한다.
- add() 메서드를 사용하여 요소를 추가할 수 있다.
- remove(), removeAll() 메서드를 사용하여 요소를 삭제할 수 있다.
[ 인덱스 접근 ]
- Iterator는 인덱스에 직접 접근하는 기능을 제공하지 않는다.
- ListIterator는 현재 위치의 인덱스를 확인하고 현재 위치의 다음과 이전 인덱스를 확인할 수 있다.
- nextIndex() 메서드를 사용하여 다음 인덱스를 확인할 수 있다.
- previousIndex() 메서드를 사용하여 이전 인덱스를 확인할 수 있다.
[ 컬렉션 타입 ]
- Iterator는 모든 Collection 인터페이스의 하위 인터페이스를 지원한다.
- ListIterator는 List 인터페이스를 구현한 컬렉션 클래스에서만 사용할 수 있다.
주니어 자바 개발자를 위한 100가지 질문 (3. Multi-Thread)_1
📌 병렬과 동시성의 차이점은 무엇인가? [ 병렬 ] 여러 작업이 실제로 동시에 실행되는 것이다. 컴퓨터 시스템에서는 여러 개의 프로세서나 코어를 사용하여, 여러 작업을 동시에 처리함으로써
dev-density.tistory.com
'Java' 카테고리의 다른 글
주니어 자바 개발자를 위한 100가지 질문 (3. Multi-Thread)_2 (0) | 2024.02.07 |
---|---|
주니어 자바 개발자를 위한 100가지 질문 (3. Multi-Thread)_1 (1) | 2024.02.06 |
주니어 자바 개발자를 위한 100가지 질문 (2. Container)_1 (0) | 2023.11.09 |
주니어 자바 개발자를 위한 100가지 질문 (1. 기초)_2 (0) | 2023.11.07 |
주니어 자바 개발자를 위한 100가지 질문 (1. 기초)_1 (0) | 2023.11.06 |