개발/Spring

자바 컬렉션 List

728x90

자료구조 : Data Structure. 어떤 정보를 담는 것을 의미.

어떻게 보면 DTO도 자료를 담는 한 방식이라고 볼 수 있다.

 

하나의 데이터가 아닌 여러 데이터를 담을 때 사용한다.

 

자바에서의 데이터를 담는 자료 구조는 크게 다음과 같다.

 

  • 순서가 있는 목록형
  • 순서가 중요하지 않은 셋형
  • 먼저 들어온 것이 먼저 나가는 큐형
  • 키값으로 저장되는 맵형

자바에서는 "목록","세트", "큐"는 Collection이라는 인터페이스를 구현하고 있다. 이 Collection 인터페이스는 java.util 패키지 안에 선언되어 있으며, 여러 개의 객체를 하나의 객체에 담아 처리할 때 공통적으로 사용되는 여러 메소드들을 선언해 놓았다. 이 목록에서 유일하게 맵 만이 Collection과 관련 없는 별도의 인터페이스로 선언 되어 있다.

 

자바의 컬렉션은 개발하면서 매우 중요하다. 잘 쓰면 약이 되고 잘 못쓰면 독이 된다. 

 

먼저 목록과 셋 큐의 기본이 되는 Collection 인터페이스에 대해서 살펴보면

 

Collection인터페이스는 다음과 같이 선언되어 있다.

 

public interface Collection<E> extends Iterable<E>

 

 

Collection 인터페이스 선언문에서 특이한 것은 Interable<E>라는 인터페이스를 extends 했다는 점이다.

Iterable 인터페이스에 선언 되어 있는 메소드는 단지 하나다.

 

iterator() 라는 메소드만 Iterable 인터페이스에 선언되어 있고, 이 메소드는 Iterator라는 인터페이스를 리턴한다.

 

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

 

이제 Collection 인터페이스에 선언되 주요 메소드를 살펴보면

 

  • add : 요소를 추가한다
  • addAll : 매개 변수로 넘어온 컬렉션의 모든 요소를 추가한다.
  • clear() : 컬렉션에 있는 모든 요소 데이터를 지운다 
  • contains : 매개변수로 넘어온 객체가 해당 컬렉션에 있는지 확인
  • containsAll : 매개변수로 넘어온 객체들이 해당 컬렉션에 있는지 확인. 매개변수로 넘어온 컬렉션에 있는 요소들이 동일한 값들이 모두 있으면 true 리턴
  • equals : 매개변수로 넘어온 객체와 같은 객체인지 확인한다.
  • hashCode : 해시 코드값을 리턴한다.
  • isEmpty() : 컬렉션이 비어있는지 확인한다. 비어있으면 true
  • iterator() : 데이터를 한 건씩 처리하기 위한 Iterator객체를 리턴한다.
  • remove(Object) : 매개변수와 동일한 객체를 삭제한다.
  •  

자바 컬렉션의 상속구조

 

List 인터페이스와 그 동생들

 

목록은 List 인터페이스로부터 시작되며, 이 List인터페이스는 방금 배운 Collection 인터페이스를 확장하였다.

 

몇몇 추가된 메소드를 제외하고 Collection에 선언된 메소드와 큰 차이는 없다.

 

Collection을 확장한 다른 인터페이스와 List인터페이스의 가장 큰 차이점은 배열처럼 순서가 있다는 것이다.

 

List 인터페이스를 구현한 클래스들은 매우 많은데 그 많은 클래스들 중에서 java.util 패키지에서는 ArrayList, Vector, Stack, LinkedList를 많이 사용한다. (순서가 있는 것들)

 

이 중에서 ArrayList, Vector 클래스는 사용법 거의 동일하고 기능도 거의 비슷함.

 

클래스의 사용법은 거의 동일하고 기능도 거의 비슷하다. 이 두 클래스는 확장 가능한 배열 이라고 생각하면 된다.

 

두 클래스의 탄생 시기를 살펴보면 Vector은 JDK 1.0부터 있었고, ArrayList는 JEK 1.2부터 추가되었다. 그리고 ArrayList의 객체는 여러명이 달려들어 값을 변경하려고 하면 문제가 생길 수 있다. ArrayList는 쓰레드 세이프 하지 않고, Vector은 쓰레드 세이프하다.

 

그 다음에 있는 Stack이라는 클래스는 Vector 클래스를 확장하여 만들었다. 이 클래스를 만든 가장 큰 이유는 LIFO를 지원하기 위함이다.

가장 마지막에 추가한 값을 가장 처음 빼 내는 것이다.

 

프로그래밍 언어에서 스택이라는 의미는 보통 메소드가 호출된 순서를 기억하는 장소를 말한다.

 

그 다음엔 LinkedList라는 클래스가 있는데, 이 클래스는 목록에도 속하지만 큐에도 속한다 .

 

 

ArrayList

 

컬렉션, 쓰레드, IO, 네트워크 관련 클래스를 사용할 때에는 한번 정도 그 클래스의 상속 관계를 살펴보는 것이 좋다.

 

왜냐하면 그 클래스의 API에 있는 메소드나 상수나 사용할 수 있는 것이 아니고, 부모 클래스에 선언되어 있는 메소드는 사용할 수 있기 때문이다.

 

게다가 컬렉션 관련 클래스의 선언부만 보더라도, 그 클래스가 목록에 속하는지 셋에 속하는지 알 수 있다. 앞으로 자바 개발하면서 상속 관계를 확인하는 습관을 들여놓는 것이 좋다.

 

Object

ㄴAbstractCollection<E>

 ㄴAbstractList<E>

  ㄴArrayList<E>

 

 

당연한 말이지만, ArrayList의 가장 상위 부모는 Object 클래스다. Object를 제외하고 모두 추상 클래스이다.

AbstractCollection은 Collection인터페이스 중 일부 공통적인 메소드를 구현해 놓은 것이며, AbstactList는 List인터페이스 중 일부 공통적인 메소드를 구현해 놓은 것이라고 기억하고 있으면 된다.

 

ArrayList가 구현한 인터페이스는 다음과 같다.

 

Serializable : 원격으로 객체를 전송하거나, 파일에 저장할 수 있음을 지정

Clonable : Object 클래스의 clone() 메소드가 제대로 수행될 수 있음을 지정.

Iterable<E> : foreach 문장을 사용할 수 있음을 지정

Colelction<E> : 여러 객체를 하나의 객체에 담아 처리할 대의 메소드 지정

List<E> : 목록형 데이터를 처리하는 것과 관련된 메소드 지정

RandomAccess : 목록형 데이터에 보다 빠르게 접근할 수 있도록 임의로 접근하는 알고리즘이 적용된다는 것을 지정.

 

위 인터페이스를 구현했다는 것은 각 인터페이스에서 선언한 기능을 사용할 수 있다는 말이다.

 

 

ArrayList의 생성자는 3개이다.

 

확장 가능한 배열이다 따라서 배열처럼 사용하지만 대괄호는 사용하지 않고, 메소드를 통해서 객체를 넣고 빼고 조회한다.

 

 

  • ArrayList() : 객체를 저장할 공간이 10개인 ArrayList를 만든다.
  • ArrayList(Collection<? extends E> c) : 매개변수로 넘어온 컬렉션 객체가 저장되어 있는 ArrayList를 만든다.
  • ArrayList<int initalCapacity) : 매개변수로 넘어온 갯수만큼의 저장 공간을 갖는 ArrayList를 만든다.

 

대부분 서로 종류의 객체를 하나의 배열에 넣지 않고 한가지 종류의 객체만 저장한다.

 

여러 종류를 하나의 객체를 담을 때에는 되도록이면 DTO라는 클래스를 하나 만들어서 담는 것이 좋다.

 

그래서 컬렉션 관련 클래스의 객체들을 선언할 때에는 제네릭을 사용하여 선언하는 것을 권한다.

 

ArrayList<String> list1 = new ArrayList<String>();

 

JDK 7부터는 따로 타입을 적지 않고 꺽세 안에 넣어도 된다.

 

ArrayList 객체를 선언할 때 매개변수를 넣지 않으면, 초기 크기는 10이다. 따라서 10개 이상 데이터가 들어가면 크기를 늘이는 작업이 ArrayList 내부에서 자동으로 수행된다. 이러한 작업이 수행되면 애플리케이션 성능에 영향을 주게 된다. 만약 저장되는 데이터의 크기가 어느정도 예측 가능하다면 다음과 같이 예측한 초기 크기를 지정할 것을 권장한다.

 

 

ArrayList에 데이터를 담아보자.

 

boolean add(E e) : 매개변수로 넘어온 데이터를 가장 끝에 넣는다.

void add(int index, E e) 매개변수로 넘어온 데이터를 지정된 index에 넣는다.

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

boolean addAll(int index, Collection<?extends E> c) : 매개변수로 넘어온 컬렉션 데이터를 index에 지정된 위치부터 담는다.

 

 

add(E e)

이 메소드를 사용하여 배열의 가장 끝에 데이터를 담는다.

리턴되는 boolean 값은 제대로 추가되었는지 여부를 말한다.

 

add(int index, E e)

기존 위치에 있는 데이터들은 위치가 하나씩 뒤로 밀려난다. 

 

 

ArrayList는 확장된 배열 타입이기 때문에 배열처럼 순서가 매우 중요하다.

 

JVM은 모든 객체가 생성되면 그 객체가 위치하는 주소가 내부적으로 할당된다. 앞에서 toString() 메소드를 구현하지 않은 클래스의 toString() 메소드 호출 결과를 출력하면 주소가 나오는 것을 확인했다.

 

얕은 복사와 깊은 복사 :

다른 객체에 원본 객체의 주소값만 할당하는 것은 얕은 복사 (원본에 영향을 줌), 하지만 객체의 모든 값을 복사하여 복제된 객체에 있는 값을 변경해도 원본에 영향이 없도록 할 때에는 Deep Copy를 수행한다. (원본에 영향을 안줌)

 

 

 

 

목록형 데이터를 대표하는 Collection이라는 인터페이스에 대해서 알아봤다.

Collection 인터페이스를 확장하는 인터페이스는 List, Queue, Set이 있다. 그 중에서 이 장에서는 List 인터페이스와 그 인터페이스를 구현한 ArrrayList에 대해서 살펴봤다.

 

 

 

 

ArrayList에서 데이터를 꺼내자

 

배열에 넣을수 있는 공간의 갯수를 가져올 때에는 배열.length를 사용한다. 그리고 String문자열의 길이를 가져오는 것도 length메소드를 사용한다,

 

하지만 Collection을 구현한 인터페이스는 size() 메소드를 통하여 들어가 있는 데이터의 갯수를 확인한다.

 

length -> 배열의 저장 공간 갯수를 의미. 

size -> 들어가 있는 데이터 갯수를 의미.

 

ArrayList 객체에 있는 데이터들을 배열로 뽑아내야 할 때

 

toArray() : 어레이리스트 객체에 있는 값들을 Object[] 타입의 배열로 만든다.

toArray(T[] a) : 매개변수로 넘어온 T타입의 배열로 만든다.

 

 

매개변수로 넘기는 배열ㅇ느 그냥 이와 같이 의미 없이 타입만을 지정하기 위해서 사용할 수도 있다.

그런데 실제로는 매개 변수로 넘긴 객체에 값을 담아준다. 하지만 ArrayList 객체의 데이터 크기가 매개변수로 넘어간 배열 객체의 크기보다 클 경우에는 매개변수로 배열의 모든 값이 null로 채워진다.

 

A,B,C를 넘길 때 :

 

5개만 할당할 경우

A B C null null

2개만 할당할 경우 (그냥 모두 Null로 채워버린다)

null null

 

이와 같은 현상 때문에 크기가 0인 배열을 넘겨주는 것이 좋다

 

 

ArrayList에 있는 데이터를 삭제하자

 

void clear() : 모든 데이터 삭제

E remove(int index) : 매개 변수에서 지정한 위치에 있는 데이터를 삭제하고 삭제한 데이터를 리턴함

boolean remove(Object o) : 첫번째 데이터를 삭제한다.

boolean removeAll(Collection<?> c) : 매개변수로 넘어온 컬렉션 객체에 있는 데이터와 동일한 모든 데이터를 삭제한다.

 

 

Stack 클래스는 뭐가 다른데?

 

 

List 인터페이스를 구현한 또 하나의 클래스인 Stack 클래스에 대해서 살펴보자. 일반적인 웹을 개발할 때에는 별로 많이 사용하지는 않지만, 마지막 들어온 데이터를 가장 처음에 꺼내는 LIFO 기능을 구현하려고 할 때 필요한 클래스이다.

 

하지만 ArrayDeque라는 클래스가 있지만 쓰레드 세이프 하지 않다. 약간 성능은 떨어지지만, 쓰레드에 안전한 LIFO 기능을 원한다면 이 Stack 클래스를 사용하면 된다. 

 

java.lang.Object

 java.uitil.AbstractCollectiopn<E>

  java.util.AbstractList<E>

   java.util.Vector<E>

    java.util.Stack<E>

 

 

Stack 클래스의 부모 클래스는 Vector이다.

즉 Vector 클래에스에서 제공하는 모든 메소드를 사용할 수 있다. 

 

Collection 인터페이스를 확장하는 인터페이스는 List, Queue, Set이 있다.

 

'개발 > Spring' 카테고리의 다른 글

스프링이란?  (0) 2021.03.14
스프링 입문을 위한 자바 객체지향 원리와 이해 - 프롤로그  (0) 2021.03.13
Spring 라이브러리  (0) 2021.03.07
아파치 톰캣  (0) 2021.03.07
Java 8의 새로운 것들, 변경된 것들.  (0) 2021.03.07