스택! ADT로서의 스택 이야기는 지겹다!
벡터 이야기부터 좀 해 보자.
자바의 스택 클래스는 벡터를 상속한다.
그래서 스택은 벡터의 모든 기능을 포함한다.
벡터가 뭘까?
(참고로 난 Vector를 1도 모른다. 그래서 이 글이 매우 길어질 것 같다.)
우선 이게 도대체 어떤 인터페이스를 구현하고 있는 클래스인지 알아 봤다.
(geeksforgeeks... 옛날(?)에는 이상한(?) 글만 올라와 있는 광고 사이트라 생각했는데 지금은 가장 마음에 드는 퀄리티의 콘텐츠를 제공한다.)
벡터가 리스트를 구현한다고???
리스트는 또 콜렉션을, 콜렉션은 또 이터러블을 상속하네...
그럼 어떻게 한다? 싹 다 뒤져 본다...
Iterable 인터페이스
Iterable 인터페이스는 Java의 모든 콜렉션 루트 인터페이스 중 하나로, 콜렉션이 반복 가능하다는 것을 나타냅니다. 이 인터페이스를 구현하는 클래스는 iterator() 메서드를 제공해야 하며, 이를 통해 Iterator 객체를 반환해서 컬렉션의 요소를 순회할 수 있습니다.
Collection 인터페이스
Collection 인터페이스는 Java 콜렉션 프레임워크의 핵심 인터페이스 중 하나로, 다양한 콜렉션의 공통된 행동을 정의합니다. 이 인터페이스는 요소 추가, 삭제, 크기 조회, 비어 있는지 확인하는 기본 메서드를 제공하며, List, Set, Queue 등 다른 콜렉션 인터페이스의 상위 인터페이스 역할을 합니다.
List 인터페이스
List 인터페이스는 요소들이 정해진 순서로 저장되고, 인덱스를 통해 리스트 내 요소에 접근할 수 있도록 하는 콜렉션을 정의합니다. List를 구현하는 클래스(예: ArrayList, LinkedList)는 요소의 추가, 삭제, 검색 등의 작업을 인덱스 기반으로 수행할 수 있습니다.
Iterable 인터페이스가 있어 순회가 가능하고, Collection 인터페이스가 있어 기본적인 메서드 사용이 가능하고, List 인터페이스가 있어 인덱스를 통한 작업이 가능하다...
그럼 다시 돌아가서, 벡터가 뭔데?
Java의 Vector 클래스는 자바 초기 버전부터 제공된 컬렉션(컬렉션 아니고 콜렉션이다. 그런데 일일이 고치기 귀찮으니 그냥 둔다.) 프레임워크의 일부입니다. Vector는 동적 배열을 구현하는 클래스로, 배열과 유사하지만 크기가 자동으로 조절되는 특성을 가지고 있습니다. 이 클래스는 java.util 패키지에 속해 있으며, List 인터페이스를 구현합니다. Vector의 주요 특징과 메서드를 살펴보겠습니다.
=> 벡터는 배열이다. 그런데 동적 배열. 그럼 ArrayList랑 뭐가 다른가?
- 동기화: 벡터의 메소드들은 동기화되어 있어서 멀티 스레드 환경에서 하나의 스레드만이 벡터의 메소드를 실행할 수 있게 합니다. 반면에 어레이리스트는 동기화되지 않아서 실행 속도가 더 빠릅니다. 멀티 스레드 환경에서는 어레이리스트를 사용할 때 외부에서 동기화를 처리해야 합니다.
- 성능: 벡터는 동기화 때문에 어레이리스트보다 일반적으로 성능이 떨어집니다. 어레이리스트는 동기화 오버헤드가 없어서 더 빠른 성능을 제공합니다.
- 크기 증가 방식: 벡터와 어레이리스트 모두 배열의 크기를 동적으로 조정할 수 있지만, 벡터는 기본적으로 용량이 100% 증가하고(용량이 부족할 때), 어레이리스트는 기본적으로 50% 증가합니다. 이 비율은 생성자를 통해 조정할 수 있습니다.
주요 특징
- 동적 배열: Vector는 내부적으로 배열을 사용하여 데이터를 저장합니다. 데이터를 추가하거나 삭제할 때 내부 배열의 크기를 자동으로 조정합니다.
- 동기화: Vector의 메서드들은 스레드 안전(thread-safe)하도록 동기화되어 있습니다. 이는 여러 스레드가 동시에 Vector에 접근하더라도 안전하게 데이터를 읽고 쓸 수 있음을 의미합니다. 그러나 이로 인해 ArrayList와 비교했을 때 성능이 떨어질 수 있습니다.
- 접근 및 수정: Vector는 get(int index), set(int index, E element), add(E element), remove(int index) 등의 메서드를 제공하여 배열 요소에 접근하고 수정할 수 있습니다.
주요 메서드
- add(E e): 벡터의 끝에 요소를 추가합니다.
- add(int index, E element): 지정된 위치에 요소를 삽입합니다.
- remove(int index): 지정된 위치의 요소를 제거하고 반환합니다.
- remove(Object o): 특정 객체를 찾아 제거합니다.
- get(int index): 지정된 위치의 요소를 반환합니다.
- set(int index, E element): 지정된 위치에 요소를 저장합니다.
- size(): 벡터의 현재 크기를 반환합니다.
- capacity(): 벡터의 현재 용량을 반환합니다. 용량은 벡터가 저장할 수 있는 최대 요소 수를 의미하며, 필요에 따라 자동으로 증가합니다.
- isEmpty(): 벡터가 비어있는지 확인합니다.
- clear(): 벡터의 모든 요소를 제거합니다.
import java.util.Vector;
public class Main {
public static void main(String[] args) {
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(1, 5); // 인덱스 1에 5 삽입, 나머지는 밀림
System.out.println("Vector: " + vector);
System.out.println("Size: " + vector.size());
System.out.println("Element at index 1: " + vector.get(1));
vector.remove(1); // 인덱스 1의 요소 제거
System.out.println("After removal: " + vector);
System.out.println("Capacity: " + vector.capacity());
}
}
그럼 언제 Vector를 사용할까?
- 멀티스레드 환경에서 안전한 구현이 필요할 때 Vector를 사용할 수 있습니다. 그러나 현대 자바 프로그래밍에서는 보다 세련된 동시성 컬렉션(예: ConcurrentHashMap, CopyOnWriteArrayList 등)을 사용하는 것이 좋습니다.
- Vector는 레거시 코드에서 여전히 사용되고 있으나, 새로운 Java 애플리케이션을 개발할 때는 ArrayList나 다른 동시성 컬렉션을 사용하는 것이 일반적입니다.
Vector의 사용은 그 편리성과 함께 몇 가지 단점을 가지고 있기 때문에, 사용할 컬렉션을 결정할 때는 애플리케이션의 요구 사항과 환경을 잘 고려해야 합니다. 자바 컬렉션 프레임워크 내 다른 컬렉션들과 비교해보고, 자신의 필요에 가장 적합한 선택을 하는 것이 중요합니다.
오... 그렇다면 Vector만 가진 메서드라든가 하는 것들은 알아보지 않겠다.
코테에서 굳이 Vector를 쓸 생각을 안 해도 되겠다.
아래 내용은 상식 수준에서만 알아 두자.
Vector와 Stack의 관계
- 상속: Stack 클래스는 Vector 클래스를 확장합니다. 즉, Stack은 Vector의 모든 속성과 메서드를 상속받아 그대로 사용할 수 있습니다.
- 추가 기능: Stack은 Vector의 기능에 더해, 스택 자료구조의 LIFO (Last In First Out) 특성을 지원하는 메서드를 추가로 제공합니다. 예를 들어, push(), pop(), peek(), empty(), search() 등의 메서드가 있습니다.
왜 Stack이 Vector를 상속받을까?
Vector는 동기화된 메서드를 제공하는 동적 배열 구현입니다. 초기 Java에서는 Vector의 동적 배열 기능과 동기화된 접근을 이용하여 쉽게 스택 구현을 추가할 수 있었습니다. Stack이 Vector를 상속받는 것은 Stack에 필요한 동적 배열 관리 기능(자동 크기 조절, 요소 추가 및 삭제 등)과 스레드 안전성을 바로 활용할 수 있기 때문입니다.
비슷한 점과 차이점
- 비슷한 점: Stack은 Vector의 모든 메서드와 속성을 사용할 수 있습니다. 따라서 Stack 객체에서는 addElement(), elementAt(), removeElement() 등 Vector의 배열 관리 기능을 그대로 사용할 수 있습니다.
- 차이점: Stack은 스택 자료구조의 특성에 맞게 몇 가지 메서드를 추가로 제공합니다. 이 메서드들은 스택의 사용법에 맞게 LIFO 방식을 강조합니다. 예를 들어, push() 메서드는 addElement()와 유사하지만, 스택의 사용법에 맞춰 이름이 지정되어 있습니다.
그럼 Stack 사용법만 알아두면 되나?
현재 사용 권장 사항
현대 Java에서는 Stack 클래스보다는 Deque 인터페이스의 구현체인 ArrayDeque 사용을 더 권장합니다. ArrayDeque는 스택과 큐의 기능을 모두 제공하며, Vector와 Stack에 비해 더 빠르고 일관된 성능을 제공합니다. 또한 ArrayDeque는 비동기화되어 있어 필요한 경우 클라이언트 측에서 동기화를 관리할 수 있어 더 유연합니다.
'자바 > 자바 자료구조' 카테고리의 다른 글
[묘공단] 자바 - Queue 이야기 (0) | 2024.04.27 |
---|---|
자바 - Stack 및 Vector로 코테 푸는 법 (0) | 2024.04.27 |
자바 - Map으로 코테 푸는 법 (0) | 2024.04.26 |
자바 - Map 이야기 (0) | 2024.04.26 |
자바 - List - LinkedList 뽀개기 (0) | 2024.04.26 |