String- 불변 객체입니다.
- 문자열 연산 시 새로운 객체가 생성됩니다.
- 불변이라 멀티스레드 환경에서 비교적 안전합니다.
StringBuffer- 가변 객체입니다.
- 내부적으로 동기화를 지원해 멀티스레드 환경에서 안전합니다.
- 대신 성능은 상대적으로 느릴 수 있습니다.
StringBuilder- 가변 객체입니다.
- 동기화를 지원하지 않아 단일 스레드 환경에서 가장 빠릅니다.
대표적으로 다음 이유를 많이 설명합니다.
- 문자열 상수 풀 재사용이 가능합니다.
- 보안상 안전합니다.
- 멀티스레드 환경에서 동기화 부담이 줄어듭니다.
hashCode를 캐싱해 해시 기반 컬렉션에서 효율적입니다.
int- 기본형입니다.
null을 가질 수 없습니다.- 산술 연산에 직접 사용됩니다.
Integer- 래퍼 클래스입니다.
- 객체이므로
null을 가질 수 있습니다. - 컬렉션에 담기 위해 자주 사용됩니다.
- 기본형이 자동으로 래퍼 클래스로 변환되는 것입니다.
- 래퍼 클래스가 자동으로 기본형으로 변환되는 것입니다.
Integer가null일 때 언박싱하면NullPointerException이 발생할 수 있습니다.
Integer.valueOf()는 자주 쓰이는 정수 범위인 -128 ~ 127를 캐싱합니다.
- 캐시 범위 안에서는 같은 객체를 재사용할 수 있습니다.
- 따라서
Integer비교에==를 쓰면 의도치 않은 결과가 나올 수 있습니다. - 객체 값 비교는 항상
equals()를 사용하는 것이 안전합니다.
HashMap은 Key-Value 구조를 가지며 내부적으로 버킷 배열을 사용합니다.
- Key의
hashCode()를 구합니다. - 해시값을 기반으로 버킷 인덱스를 계산합니다.
- 해당 버킷에 데이터를 저장하거나 조회합니다.
평균적으로 조회와 저장은 O(1)에 가깝습니다.
| 구분 | HashMap | Hashtable | ConcurrentHashMap |
|---|---|---|---|
| 동기화 | 지원 안 함 | 메서드 전체 동기화 | 세분화된 동시성 제어 |
| Thread-Safe | X | O | O |
| 성능 | 단일 스레드에서 빠름 | 느림 | 멀티스레드에서 효율적 |
| null 허용 | Key, Value 가능 | 불가 | 불가 |
| 사용 권장 | 일반 상황 | 레거시 | 멀티스레드 환경 |
서로 다른 Key가 같은 버킷 인덱스로 매핑되면 충돌이 발생합니다.
- 기본적으로 같은 버킷 안에서 연결 구조로 관리합니다.
- Java 8부터는 충돌이 많아져 버킷 내 데이터 수가 임계치를 넘으면 연결 리스트를 트리 구조로 바꿔 탐색 성능을 개선합니다.
실무 면접에서는 "충돌 시 체이닝으로 처리하고, Java 8 이상에서는 필요 시 Red-Black Tree로 전환된다" 정도로 설명하면 좋습니다.