Collection 과 ArrayList

@MinSang · July 22, 2024 · 8 min read

Collection 인터페이스

img 1

자바에서 Set, List, QueueCollection 이라는 인터페이스를 구현하고 있습니다. Collection 인터페이스는 다음과 같이 선언되어 있습니다.

public interface Collection<E> extends Iterable<E>

Iterable<E>이라는 인터페이스를 extends 하였는데 이 인터페이스에 대해 잠깐 알아보겠습니다.

Iterable

이 인터페이스에 선언되어 있는 메소드는 단지 하나입니다. Iterator<T> iterator(); 이며, 이 메소드는 Iterator<T>인터페이스를 리턴합니다.

Iterator<T>인터페이스에는 추가 데이터가 있는 지 확인하는 hasNext() , 현재 위치를 다음 요소로 넘기고 그 값을 리턴해주는 next(), 데이터를 삭제하는 remove()가 있습니다.

결론적으로, Collection 인터페이스가 Iterable 인터페이스를 확장했다는 의미는 Iterator 인터페이스를 사용하여 데이터를 순차적으로 가져올 수 있다는 의미입니다.

Collection 에 선언된 주요 메소드

  • boolean add(E e) : 요소 추가
  • boolean addAll(Collection) : 매개변수로 넘어온 컬렉션 모든 요소 추가
  • void clear() : 컬렉션에 있는 모든 요소 데이터 지우기
  • boolean contains(Object) : 매개변수로 넘어온 객체와 동일한 객체가 해당 컬렉션에 있으면 true 반환
  • boolean containsAll(Collection) : 매개변수로 넘어온 컬렉션에 있는 객체들이 해당 컬렉션에 모두 동일한 값들이 있다면 true 반환
  • boolean equals(Object)
  • int hashCode()
  • boolean isEmpty()
  • Iterator iterator()
  • boolean remove(Object)
  • boolean removeAll(Collection)
  • boolean retainAll(Collection) : 매개변수로 넘어온 객체들만을 컬렉션에 남겨 둔다
  • int size() : 요소의 개수를 리턴
  • Object[] toArray() : 컬렉션에 있는 데이터들을 배열로 복사
  • <T> T[] toArray(T[]) : 컬렉션에 있는 데이터들을 지정한 타입의 배열로 복사

List 인터페이스

Collection인터페이스를 확장한 List 인터페이스는 다른 Set, Queue와 다른 점은 배열처럼 순서가 있습니다.

List 인터페이스를 구현한 클래스는 ArrayList, Vector, Stack, LinkedList 이고, 이중 ArrayList와 Vector확장 가능한 배열이며 차이점은 ArrayListThread Safe 하지 않지만 VectorThread Safe 합니다.

ArrayList

상속관계

java.lang.Objectjava.util.AbstractCollection<E>java.util.AbstractList<E>java.util.ArrayList<E>

AbstractCollectionCollection 인터페이스 중 일부 메소드를 구현해 놓은 것이며, AbstractListList 인터페이스 중 일부 메소드를 구현해놓았습니다.

ArrayList가 구현한 인터페이스

public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

추가로 Collection<E>Iterable<E> 이므로 이 인터페이스들이 선언한 메소드들을 사용할 수 있습니다.

ArrayList 생성자

  • ArrayList() : 객체를 저장할 공간이 10개인 컬렉션을 만듭니다. 단, 10개 만들었다고 랜덤으로 아무데나 넣으면 IndexOutOfBoundsException이 발생됩니다.
  • ArrayList(Collection<? extends E> c : 매개 변수로 넘어온 컬렉션 객체가 저장되어 있는 요소를 복사하여 ArrayList를 만든다
  • ArrayList(int initialCapacity) : 매개변수로 넘어온 initialCapacity 개수 만큼의 저장공간을 갖는 ArrayList를 만든다.

ArrayList에 데이터 담기

  • boolean add(E e) : 매개변수로 넘어온 데이터를 가장 끝에 담는다
  • void add(int index, E e)
  • boolean addAll(Collection<? extends E> c) : 매개변수로 넘어온 컬렉션 데이터를 가장 끝에 담는다
  • boolean addAll(int index, Collection<? extends E> c)

얕은 복사 vs 깊은 복사

ArrayList<String> list = new ArrayList<>();
list.add("A");

ArrayList<String> list2 = list;

위 코드와 같이 다른 객체에 원본 객체의 주소만을 할당하는 것은 얕은 복사 입니다. 이렇게 하면 원본 객체에서 요소가 추가되었을 때 list2 역시 반영됩니다.

반면, 객체의 모든 값을 복사하여 복제된 객체에 있는 값을 변경해도 원본에 영향을 없도록 할 때에는 깊은 복사 이며, 아래와 같이 할 수 있습니다.

ArrayList<String> list = new ArrayList<>();
list.add("A");

ArrayList<String> list2 = new ArrayList<>(list);

ArrayList<String> list3 = new ArrayList<>();
list3.addAll(list);

ArrayList에서 데이터 꺼내기

  • E get(int index)
  • int indexOf(Object o)
  • int lastIndexOf(Object o)
  • int size()

ArrayList 객체에 있는 데이터를 배열로 뽑아낼 때 다음 메소드들을 사용할 수 있습니다.

  • Object[] toArray() : ArrayList 객체에 있는 값들을 Object[] 타입의 배열로 만든다
  • <T> T[] toArray(T[] a) : ArrayList 객체에 있는 값들을 매개 변수로 넘어온 T 타입의 배열로 만든다

단, toArray()는 Object 타입의 배열로만 리턴하므로 제네릭을 사용하여 선언한 ArrayList 객체를 배열로 생성할 때는 <T> T[] toArray(T[] a)를 사용하는 것이 좋습니다.

ArrayList<String> list = new ArrayList<>();
list.add("A");
String[] strList = list.toArray(new String[0]);

코드에서 new String[0]은 의미없는 빈 배열의 타입을 넣었습니다. 왜냐하면 만약 다음과 같이 공간이 큰 배열을 넣으면 빈 공간에 null이 채워지고, 작은 경우엔 딱 그 크기만큼만 배열로 변환됩니다.

ArrayList<String> list = new ArrayList<>();
list.add("1");

String[] tempArray = new String[3];
String[] strList = list.toArray(tempArray);

for (String temp : strList) {
    System.out.println("temp = " + temp);
}
// 출력 : 1 null null

ArrayList<String> list2 = new ArrayList<>();
list2.add("1");
list2.add("2");

String[] tempArray2 = new String[1];
String[] strList2 = list.toArray(tempArray2);

for (String temp : strList2) {
    System.out.println("temp = " + temp);
}
// 출력 : 1

따라서 toArray() 메소드를 사용할 때엔 크기가 0인 배열로 넘겨주는 것이 좋습니다.

ArrayList에 있는 데이터 삭제

  • void clear()
  • E remove(int index)
  • boolean remove(Object o) : 매개변수에 넘어온 객체와 동일한 첫 번째 데이터를 삭제한다
  • boolean removeAll(Collection<?> c) : 매개변수로 넘어온 컬렉션에 있는 데이터와 동일한 모든 데이터를 삭제한다

ArrayList에 있는 값 변경

  • E set(int index, E element) : 지정한 위치에 있는 데이터를 두 번째 매개변수로 넘긴 값으로 변경한다. 그리고, 해당 위치에 있던 데이터를 리턴한다

ArrayList Thread safe 하게 만들기

List list = Collections.synchronizedList(new ArrayList(...));

Reference

@MinSang
지식과 경험을 기록하는 TIL 저장소