2023. 3. 20. 17:13ㆍjava일지
2023/03/20
- 학습내용
프로그램을 개발할 때 사용하는 자료를 어떤 구조로 관리할 것인지가 중요하다.
프로그램의 기능을 효과적으로 구현할 수 있기 때문이다.
이 때 사용하는 것이 자료 구조(data structure)다.
자료 구조는 프로그램 실행 중 메모리에 자료를 유지·관리하기 위해 사용한다.
JAVA에서는 필요한 자료 구조를 미리 구현하여 java.util 패키지에서 제공하고 있는데,
이를 컬렉션 프레임워크(Collection Framework)라고 한다.
1. 컬렉션 프레임워크

컬렉션 프레임워크는
개발자가 직접 자료 구조를 만드는 수고를 덜 수 있을 뿐만 아니라 잘 만들어진 자료 구조 클래스를 활용할 수 있게 해준다.
컬렉션 프레임워크에는 여러 인터페이스가 정의되어 있고, 그 인터페이스를 구현할 클래스가 있다.
컬렉션 프레임워크의 전체 구조는 Collection 인터페이스와 Map 인터페이스 기반으로 이루어져 있다.
Collection 인터페이스는 하나의 자료를 모아서 관리하는데 필요한 기능을 제공한다.
Map 인터페이스는 쌍(pair)으로 된 자료들을 관리하는데 유용한 기능을 제공한다.
1) Collection 인터페이스

List를 구현한 클래스는 순차적인 자료를 관리하는 데 사용하는 클래스다.
Set 인터페이스는 우리가 수학 시간에 배운 집합이라고 생각하면 된다.
집합은 순서와 상관없이 중복을 허용하지 않는다.
※ Collection 인터페이스에 선언된 메서드

2. List 인터페이스
List 인터페이스에는 객체를 순서에 따라 저장하고 유지하는 데 필요한 메서드가 선언되어 있다.
주로 배열들이 List 인터페이스에 있다.
1) ArrayList 클래스

객체 배열을 구현한 클래스이며 컬렉션 인터페이스와 그 하위 List 인터페이스를 구현했다.
객체 순서를 기반으로 순차적으로 자료를 관리하는 프로그램을 구현할 때 사용한다.
※ 배열 용량(capacity)
(ArrayList list = new ArrayList()와 같이 생성자를 호출할 때 ArrayList가 생성되는 과정)
ArrayList.java 파일을 보면,
객체 배열로 사용할 Object 배열(elementData)과 디폴트 용량(DEFAULT_CAPACITY)이 정의되어 있다.
ArrayList() 디폴트 생성자를 호출하여 배열 크기를 지정하지 않으면 크기가 10개짜리 배열이 기본으로 만들어진다.
이를 배열 용량(capacity)이라고 한다.
ArrayList(int) 생성자를 사용하면 초기에 생성할 배열의 용량을 지정할 수 있다.
배열에 요소를 추가하여 3개 항목이 있다고 할 때 size() 메서드를 호출하면 유효한 값이 저장된 요소 개수 3이 반환된다.
이는 배열 용량과는 다른 의미다.
ex) 호텔이 1인실이 10개 있는데 손님 3명이 투숙한다고 해서 방이 3개인 것은 아니니까 말이다.
ArrayList에 요소를 추가하면 처음 생성한 용량이 부족할 수 있다.
<기본으로 10개가 만들어진 경우 11번째 요소를 추가하면 어떻게 될까?>
ArrayList의 요소가 추가되는 add()나 insert() 등의 메서드는 용량이 부족하면 큰 용량의 배열을 새로 만들고 기존 항목을 복사한다.
2) Vector 클래스
Vector 는 자바2 이전부터 제공했으며 ArrayList 처럼 배열을 구현한 클래스다.
ArrayList와 Vector 의 차이는 동기화 지원 여부이다.
동기화(synchronization)는 두 개 이상의 스레드가 동시에 Vector 를 사용할 때 오류가 나지 않도록 실행 순서를 보장한다.
※ 동기화(synchronization)
두 개 이상의 스레드, 멀티 스레드가 동시에 실행되면 같은 메모리 공간에 접근하기 때문에 변수 값이나 메모리 상태에 오류가 발생할 수 있다.
이때 메모리에 동시에 접근하지 못하도록 순서를 맞추는 것이 동기화다.
두 작업이 동시에 실행되는 멀티스레드 환경이 아닌 경우에는 ArrayList를 사용하도록 권장한다.
이유는 동기화를 구현하기 위해서는 동시에 작업이 이루어지는 자원에 대해 잠금(lock)을 수행하기 때문이다.
즉 메서드를 호출할 때 배열 객체에 잠금을 하고, 메서드 수행이 끝나면 잠금을 해제하는 것이다.
Vector의 모든 메서드는 호출될 때마다 잠금과 해제가 일어나므로 ArrayList보다 수행 속도가 느리다.
ArrayList를 사용해서 구현했는데 나중에 프로그램 동기화가 필요하다면 Vector로 바꾸지 않고 다음 ArrayList 생성 코드를 쓰면 된다.
Collections.synchronizedList(new ArrayList<String>());
3) LinkedList 클래스
LinkedList 는 배열의 크기나 순서면에서 정적인 부분을 개선한 자료 구조이다.
LinkedList 의 각 요소는 다음 요소를 가리키는 주소 값을 가진다.

링크드 리스트의 각 요소는 다음 요소를 가리키는 주소 값을 가진다.
물리적인 메모리는 떨어져 있어도 논리적으로는 앞뒤 순서가 있다.
같은 List 인터페이스를 구현한 ArrayList에 비해 중간에 자료를 넣고 제거하는 데 시간이 적게 걸린다는 장점이 있다.
또한, 크기를 동적으로 증가시킬 수 있다.
링크드 리스트의 각 요소는 자료와 다음 요소의 주소를 저장하는 부분으로 구현된다.
(1) 링크드 리스트에 요소 추가하기

링크드 리스트의 3번째 위치에 C 요소를 추가했다.
배열이라면 D 요소를 뒤로 밀고 공간을 비워서 그 자리에 C를 놓는다.
하지만 링크드 리스트는 서로 가리키고 있는 주소 값만 변경해 주면 된다.
B가 가리키던 다음 위치를 C로 변경하고 C는 D를 가리키면 된다.
그러면 논리적으로 A -> B -> C -> D 순서가 된다.
(2) 링크드 리스트에 요소 제거하기

요소를 제거하는 경우에도 각 요소가 가리키는 주소 값만 변경하면 된다.
B를 제거한다고 할 때 A의 다음 요소를 C로 변경하기만 하면 A -> C -> D 순서가 된다.
이때 제거된 B의 메모리는 나중에 자바의 가비지 컬렉터에 의해 수거된다.
(3) 배열과 링크드 리스트 차이
배열은 생성할 때 용량을 지정하고, 용량보다 더 많은 요소가 추가된 경우에 용량을 늘려 가며 수행한다.
링크드 리스트는 요소를 추가할 때마다 동적으로 요소의 메모리를 생성한다.
배열처럼 용량을 늘리고 요소 값을 복사하는 번거로움이 없는 것이다.
사용하는 자료의 변동(삽입, 삭제)이 많은 경우에는 링크드 리스트를 사용하고,
자료 변동이 거의 없는 경우에는 배열을 사용하는 것이 효율적이다.
(4) 링크드 리스트 클래스 사용하기
//LinkedList 테스트
package collection;
import java.util.LinkedList;
public class LinkedListTest {
public static void main(String[] args) {
LinkedList<String> myList = new LinkedList<String>();
myList.add("A"); //링크드 리스트에 요소 추가
myList.add("B");
myList.add("C");
System.out.println(myList); //리스트 전체 출력
myList.add(1, "D"); //링크드 리스트의 첫 번째 위치에 D추가
System.out.println(myList);
myList.addFirst("0"); //링크드 리스트의 맨 앞에 0추가
System.out.println(myList);
System.out.println(myList.removeLast()); //링크드 리스트의 맨 뒤 요소 삭제 후 해당 요소 출력
System.out.println(myList);
LinkedList 클래스에는 링크드 리스트의 맨 앞 또는 맨 뒤에 요소를 추가,삭제하는 addFirst(), addLast(), removeFirst(), removeLast() 등의 메서드가 있다.
4) Collection 요소를 순회하는 Iterator
Iterator는 Collection 인터페이스를 구현한 객체에서 미리 정의되어 있는 iterator()메서드를 호출하여 참조한다.
Iterator ir = memberArrayList.iterator();
ex) Collection을 구현한 ArrayList에 iterator()메서드를 호출하면 Iterator 클래스가 반환되므로 Iterator형 변수에 대입해 사용한다.
※ Iterator를 사용하여 요소를 순회할 때 사용하는 메서드
| boolean hasNext() | 이후에 요소가 더 있는지를 체크하는 메서드이며, 여소가 있다면 true를 반환 |
| E next() | 다음에 있는 요소를 반환 |
Iterator 메서드 사용 예시
// Iterator 메서드 사용 ex)
public boolean removeMember(int memberId) { //Iterator 반환
Iterator<Member> ir = arrayList.iterator(); //요소가 있는 동안
while(ir.hasNext()) { //다음 회원을 반환받음
Member member = ir.next();
int tempId = member.getMemberId(); //회원 아이디가 매개변수와 일치하면
if(tempId == memberId) { //해당 회원 삭제
arrayList.remove(member); //true 반환
return true;
}
}
//끝날 때까지 삭제하려는 값을 찾지 못한 경우
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
arrayList.iterator() 메서드를 호출하여 Iterator 를 가져온다.
Iterator<Member>와 같이 제네릭 자료형으로 Iterator 가 순회할 요소의 자료형을 지정한다.
Iterator 는 각 요소를 순회하기 때문에 hashNext()의 결과가 true이면 다음 요소를 가져오는 next()메서드를 호출한다.
이렇게 순서가 없는 클래스도 Iterator 를 사용하면 요소를 순회할 수 있다.
'java일지' 카테고리의 다른 글
| 자바 리마인드#19 람다식 (0) | 2023.04.06 |
|---|---|
| 자바 리마인드#16 제네릭(Generic) 프로그래밍 (0) | 2023.03.13 |
| 자바 리마인드#15 기본 클래스(2) (0) | 2023.03.09 |
| 자바 리마인드#14 기본 클래스(1) (0) | 2023.03.09 |
| 자바 리마인드#13 인터페이스 활용 (0) | 2023.02.07 |