Open glenn-syj opened 2 months ago
ArrayList가 내부에 별도로 Itr, ListItr을 구현해서 사용하고 있는줄은 몰랐는데, 생각지 못한 부분을 언급해주셔서 덕분에 공부가 되었습니다! 확인해보니 말씀해주신것처럼 AbstractList 내부의 Iterator에서는 next()나 previous()를 사용할때 get() 메서드를 사용해 요소에 접근하는 것을 확인했습니다.
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i); // get()으로 가져옵니다!
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException(e);
}
}
사실 get()메서드가 추상메서드이기 때문에 어떻게 구현하느냐에 따라 속도는 차이가 있겠지만, ArrayList는 데이터가 배열 형태로 저장되어있어 배열에 직접 접근하는 형태이기 때문에 당연히 속도가 빠르다는 점이 이해가 되었습니다. Iterator라는 개념은 아직 낯설지만 용도에 따라 유용하게 사용해볼 수 있을 것 같네요! 감사합니다!
based on: #215 by @yngbao97
들어가며
Java에서 반복문을 이용할 때 for문, for-each문, while문은 익숙할 만큼 자주 사용하게 됩니다. 그러나 @yngbao97 님의 글에서도 언급되었듯이
Iterator
자체가 익숙하지는 않습니다. 사실Iterator
및Iterable
인터페이스가 Java Collections에서 중요한 역할을 담당하고 있음에도 말입니다. 따라서 이번 글에서는, Java Collection에서Iterator
를 어떻게 지원하는지ArrayList
클래스를 통해 살펴보겠습니다.ArrayList가 Iterator를 지원하는 방식
ArrayList는
AbstractList
추상 클래스를 상속받으며,AbstractList
에 이미 존재하는Iterator
인터페이스 구현 클래스Itr
이나ListItr
를 이용하지 않습니다.ArrayList
자체적으로 내부 클래스Itr
또는ListItr
를 만들어서 이용하는데요.Iterator 구현체 Itr
Itr 클래스는 단방향(인덱스가 적은 곳에서 큰 곳으로)으로의 순회를 지원합니다. 즉, 순차적으로 탐색할 때 이용됩니다. 그런데 코드에서도 볼 수 있듯이, 삭제는 가능하지만 수정은 불가능합니다. 양방향 탐색도 불가능합니다.
특히, 삭제를 담당하는
remove()
메서드는 현재 커서가 있는 곳이 아니라 이전lastRet
위치의 요소를 삭제하고, 커서를lastRet
인덱스에 둡니다. 이러한 방식으로 안전하게 요소를 삭제할 수 있습니다. 동시성에서 비롯되는 예외처리를 한 것도 인상적입니다.checkForModification()
은modCount
를 이용해 외부에서 수정이 일어났는지 확인하는 메서드입니다.ListIterator 구현체 ListItr
ListItr
은ListIterator
의 구현체입니다. 여기에서는 양방향 탐색과 함께 요소의 수정, 추가, 삭제가 모두 지원됩니다. 게다가 이전 인덱스 역시 조회할 수 있습니다.AbstractList 내부 Iterator와의 차이
AbstractList
내부의Itr
클래스는get()
메서드를 이용해 요소를 반환하는 반면,ArrayList
내부의Itr
클래스는 배열에 직접 접근해 요소를 반환합니다. 이는 당연하게도,ArrayList
클래스의 특성 상 배열로 참조해 더 빠르게 접근할 수 있는 까닭입니다. 따라서 O(1)의 시간 복잡도로 접근할 수 있습니다.