자바 컬렉션(Java Collections)
: 자바에서 데이터를 효과적으로 저장하고 관리할 수 있도록 도와주는 프레임워크이다. 켈렉션을 여러 개의 객체를 모아 놓은 데이터 구조를 의미하고, 자바 컬렉션 프레임워크는 이러한 컬렉현을 쉽게 사용할 수 있는 여러 클래스와 인터페이스를 제공한다.
1. 컬렉션 프레임워크의 구성 요소
- Collection 인터페이스 : 모든 컬렉션의 최상위 인터페이스[1]*로, 리스트, 셋, 큐 등 여러 하위 인터페이스를 포함한다. 리스트(List), 셋(Set), 큐(Queue) 등 여러 하위 인터페이스를 포함한다.
- Map 인터페이스 : 키-값 쌍으로 데이터를 저장하는 구조호, Collection과는 다르다. 키는 중복될 수 없고, 각 키에 대해 하나의 값만 연결한다.
2. 주요 인터페이스 및 클래스
- Collection 인터페이스의 하위 인터페이스
1) List : 순서가 있는 데이터의 집합으로, 중복된 요소를 허용한다.
1-1) ArrayList : 배열 기반의 리스트로, 인덱스를 통해 빠르게 접근할 수 있다. 하지만 요소를 추가하거나 제거할 때, 성능이 떨어질 수 있따.
+-----+-----+-----+-----+-----+
| 0 | 1 | 2 | 3 | 4 |
+-----+-----+-----+-----+-----+
| A | B | C | D | E |
+-----+-----+-----+-----+-----+
크기가 가변적이며, 필요에 따라 자동으로 배열의 크기를 조정한다. 요소를 추가하거나 삭제할 때 성능이 좋다. (단, 중간에 요소를 삽입하거나 삭제할 경우 성능이 저하될 수 있다.) 배열 기반이라 인덱스를 통한 접근이 빠르다.
import java.util.ArrayList;
public class Sample {
public static void main(String[] args) {
ArrayList foods = new ArrayList();
foods.add("떡볶이");
foods.add("마라탕");
foods.add("케이크");
}
}
ArrayList의 객체인 foos에 add 메서드를 이용하여 음식을 저장했다. 만약 첫 번째 위치에 돈까스를 추가하고 싶으면
foods.add(0,"돈까스")
다음과 같이 삽입할 위치를 파라미터로 넘겨줘야한다.
을 사용하면 원하는 인덱스 값을 추출할 수 있따.
get() : 해당 인덱스의 값을 추출한다.
size() : arrayList의 요소의 개수를 리턴한다.
contains() : 리스트 안에 해당 항목이 있는지 판별해 그 결과를 boolean으로 리턴한다.
remove(객체) : 리스트에서 객체에 해당하는 항목을 삭제한 뒤, 그 결과로 true 또는 false를 리턴한다.
remove(인덱스) : 리스트에서 해당하는 인덱스에 항목을 삭제한 뒤, 그 항목을 리턴한다.
sort(Comparator.naturalOrder()) : 오름차순 정렬
sort(리스트, Comparator .reverseOrder()) : 내림차순 정렬
1-2) LinkedList : 노드 구조로 이루어진 리스트로, 요소의 추가 및 삭제가 빠르다. 반면, 인덱스를 통한 접근 속도는 느리다.
+-----+------+ +-----+------+ +-----+------+ +-----+------+
| A | * | -> | B | * | -> | C | * | -> | D | * |
+-----+------+ +-----+------+ +-----+------+ +-----+------+
노드 구조는 각 요소가 객체로 표현되며, 각 노드는 다음 노드에 대한 참조(포인터)를 가지고 있다. 동적으로 크기를 조절할 수 있어, 삽입/삭제가 O(1) 시간 복잡도로 가능하며, 메모리가 필요할 때마다 할당되므로 메모리 낭비가 적다. 하지만, 인덱스를 사용하여 직접 접근할 수 없으므로, 특정 요소에 접근하기 위해서 O(n)이 걸린다. 각 노드가 추가적인 메모리를 사용하므로 메모리 오버헤드가 발생한다.
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// ArrayList 선언 및 초기화
List<String> arrayList = new ArrayList<>();
arrayList.add("사과");
arrayList.add("바나나");
arrayList.add("바나나");
// LinkedList 선언 및 초기화
List<String> linkedList = new LinkedList<>();
linkedList.add("체리");
linkedList.add("포도");
System.out.println("ArrayList: " + arrayList); //["사과", "바나나", "바나나"]
System.out.println("LinkedList: " + linkedList); //["체리", "포도"]
}
}
2) Set : 중복을 허용하지 않는 데이터의 집합이다. HashSet, LinkedHashSet, TreeSet 등이 있다.
2-1) HashSet : 해시 테이블을 기반으로 하며, 빠른 검색 성능을 제공한다.
해시 테이블:
+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+
| | A | | B | C |
+---+---+---+---+---+
해시는 키-값 쌍으로 데이터를 저장하는 구조이다. 해시 함수를 사용하여 키를 해시 값으로 변환하고, 이를 인덱스로 사용하여 데이터를 저장한다. 평균적으로 O(1) 시간 복잡도로 요소에 접근할 수 있습니다. 서로 다른 키가 같은 해시 값을 가질 경우 충돌을 처리해줘야한다. 또한 저장된 데이터 순서를 보장하지 않는다. 그래서 주로 데이터베이스 인덱싱, 캐시 시스템, 중복 제거 등에 사용한다.
2-2) TreeSet : 이진 탐색 트리를 기반으로 하며, 정렬된 순서로 요소를 유지한다.
A
/ \
B C
/ \ \
D E F
트리는 계층 구조로 데이터를 저장한다. 각 노드는 부모와 자깃 노드로 구성도며, 트리의 최상위 노드를 루트라고 한다. 정렬된 데이터로 상태를 유지하며 데이터 간의 관계를 명확히 표현할 수 있다. 균형잡힌 트리에서는 O(logn) 시간 복잡도로 검색할 수 있다.
3) Queue : FIFO 원칙에 따라 데이터를 처리한다. LinkedList가 큐를 구현할 수 있다.
+---+---+---+---+
Front | 1 | 2 | 3 | 4 |
+---+---+---+---+
Rear
먼저 들어온 데이터가 먼저 나가는 구조이고 큐는 주로 대기열을 모델링하는데 사용한다. 큐는 고정크기를 가지고 있으며, 크기를 초과하면 오버 플로우가 발생할 수 있다.
4) Map : map은 키-값 쌍으로 데이터를 저장하는 구조이며, 각 키는 고유하고 키를 통해 해당 값을 빠르게 조회할 수 있따. 중복 키가 없으며 이미 존재하는 키에 값을 추가하면 기존 값이 업데이트 된다.
map:
+-------+-------+
| 키 | 값 |
+-------+-------+
| 'a' | 1 |
| 'b' | 2 |
| 'c' | 3 |
+-------+-------+
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.HashMap;
import java.util.TreeMap;
import java.util.Map;
public class SetExample {
public static void main(String[] args) {
// HashSet 선언 및 초기화
Set<String> hashSet = new HashSet<>();
hashSet.add("사과");
hashSet.add("바나나");
hashSet.add("사과"); // 중복 추가
// LinkedHashSet 선언 및 초기화
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("체리");
linkedHashSet.add("포도");
linkedHashSet.add("체리"); // 중복 추가
System.out.println("HashSet: " + hashSet);
System.out.println("LinkedHashSet: " + linkedHashSet);
}
}
public class MapExample {
public static void main(String[] args) {
// HashMap 선언 및 초기화
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("사과", 1);
hashMap.put("바나나", 2);
hashMap.put("사과", 3); // 키 중복 시 값 업데이트
// TreeMap 선언 및 초기화
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("체리", 5);
treeMap.put("포도", 4);
System.out.println("HashMap: " + hashMap);
System.out.println("TreeMap: " + treeMap);
}
}
제너릭(Generic)
: 데이터 타입을 일반화하여 코드의 재사용성을 높이고, 타입 안정성을 제공하는 기능이다. 제너릭을 사용하면 다양한 데이터 타입을 다룰 수 있는 '틀' 을 만들 수 있다. 예를 들어 ArrayList<String> 이라고 하면, 이 리스트는 문자열만 담을 수 있다. 이렇게 하면 나중에 캐스팅 오류 방지할 수 있다.
[1]최상위 인터페이스: 자바의 클래스 구조에서 다른 모든 인터페이스의 부모 역할을 하는 인터페이스를 의미한다. 즉, 특정 인터페리스가 다른 인터페이스들의 공통된 특성을 정의하고, 그 아래에 있는 모든 하위 인터페이스가 이 최상위 인터페이스를 상속받는 구조이다.
'Java' 카테고리의 다른 글
Java 패키지 (0) | 2024.08.27 |
---|---|
Java 오버로딩 & 오버라이딩 (0) | 2024.08.27 |
Java 생성자 (0) | 2024.08.26 |
Java 변수 기본형 참조형 (0) | 2024.08.26 |
자바 기초 자료 모음 (1) | 2024.08.09 |