본문 바로가기
TIL/Java | Spring Boot

2021.12.30 TIL : [Java] 컬렉션과 제네릭 (Collection & Generic) - 1

by yeon_zoo 2021. 12. 30.

컬렉션은 자바 프로그램을 작성하는데 빼놓을 수 없는 중요한 도구이다. JDK에서는 자료구조 과목에서 배웠던 다양한 자료 구조들을 컬렉션으로 만들어서 제공하기 때문에 이를 잘 이해해두면 좋다. 컬렉션은 제네릭이라는 기법으로 구현되어 있기 때문에 컬렉션을 공부하기 위해서는 제네릭에 대한 공부도 필요하다. 

 

배열은 여러 개의 데이터를 다루는 데 편리한 자료 구조이지만, 삽입 삭제가 빈번하고 데이터의 크기를 예측할 수 없는 응용 프로그램에서 사용하기에는 불편하다. 

 

컬렉션은 배열이 가진 고정 크기의 단점을 극복하기 위해 객체들을 쉽게 삽입, 삭제, 검색할 수 있는 가변 크기의 컨테이너이다.

 

컬렉션 클래스 종류

  • vector<E>와 ArrayList<E> : 가변 크기의 배열을 구현
  • Stack<E> : 스택 구현
  • LinkedList<E> : 링크로 연결되는 리스트를 구현

위 컬렉션 클래스는 모두 Collection<E>를 상속받고, 단일 클래스 ---- 요소로 다루는 공통점이 있다. 

이와 달리 HashMap<K, V>는 키와 값의 쌍으로 이루어지는 데이터를 저장하고 키로 쉽게 검색하도록 만든 컬렉션이다. 


컬렉션의 특징

1) 컬렉션은 제네릭이라는 기법으로 만들어져 있다. 컬렉션 클래스의 이름에는 <E>, <K>, <V> 등이 항상 포함된다. 이들은 타입 매개변수라고 한다. Vector<E>에서 E 대신 Integer와 같이 구체적인 타입을 지정하면 Vector<Integer>는 정수 값만 저장하는 벡터로, Vector<String>은 문자열만 저장하는 벡터로 사용할 수 있다. 특정 타입만 다루지 않고 여러 종류의 타입으로 변할 수 있도록 일반화한 것이 <E>를 사용한다. 일반화시킨 <E>를 제네릭 타입이라고 부른다. 

 

2) 컬렉션의 요소는 객체들만 가능하다. int, char, double 등의 기본 타입의 데이터는 원칙적으로 컬렉션의 요소로 불가능하다. 

Vector<int> v = new Vector<int>(): // 컴파일 오류. int 사용 불가
Vector<Ineger> v = new Vector<Integer>(); // 정상 처리

벡터 생성

벡터를 생성할 때, Vector<E>의 E에 요소로 사용할 타입을 지정해야 한다. 예를 들어, 정수 값만 삽입 가능한 벡터를 만들고자 하면 다음과 같이 E에 Integer를 지정하여 벡터를 생성한다. 자바 버전 10 이상에서는 타입 추론이 가능해져서 var 을 이용해서 컴파일러가 변수 타입을 추론하도록 할 수도 있다.

Vector<Integer> v1 = new Vector<Integer>();

//자바 10 이상에서는 다음과 같이 줄여서도 가능
var v2 = new Vector<Integer>();

벡터 활용 예시

import java.util.Vector;

class Point{
    private int x, y;
    public Point(int x, int y){
        this.x = x; this.y = y;
    }
    public String toString(){
        return "(" + x +"," + y +")";
    }
}

public class practice_5 {
    public static void main(String args[]){
        var v = new Vector<Point>();

        v.add(new Point(2, 3));
        v.add(new Point(-5, 20));
        v.add(new Point (30, -8));

        v.remove(1);
        for (int i=0; i<v.size(); i++){
            Point p = v.get(i);
            System.out.println(p);
        }
    }
}

결과는 다음과 같다

(2,3)
(30,-8)

ArrayList는 작동법이나 특징이 Vector 클래스와 거의 동일하다. 다른 점은 ArrayList는 스레드 간의 동기화를 지원하지 않기 때문에, 다수의 스레드가 동시에 ArrayList에 요소를 삽입하거나 삭제할 때 데이터가 훼손될 우려가 있다. 하지만 멀티스레드 동기화를 위한 시간 소모가 없기 때문에 Vector보다 속도가 빠르다. 따라서 단일 스레드 응용에는 더 효과적이다. 

 

ArrayList 활용 예시

import java.util.*;

public class practice_6 {
    public static void main(String args[]){
        var a = new ArrayList<String>();

        Scanner s = new Scanner(System.in);
        for (int i=0; i<4; i++){
            System.out.print("이름을 입력하세요>> ");
            String str = s.next();
            a.add(str);
        }
        for (int i=0;i<a.size(); i++){
            String name = a.get(i);
            System.out.print(name + " ");
        }

        int longestIndex = 0;
        for (int i=1; i <a.size(); i++){
            if (a.get(longestIndex).length() < a.get(i).length()){
                longestIndex = i;
            }
        }
        System.out.println("\n가장 긴 이름은 :" + a.get(longestIndex));
        s.close();
    }
}

실행 결과

이름을 입력하세요>> ironman
이름을 입력하세요>> spiderman
이름을 입력하세요>> doctorstrange
이름을 입력하세요>> hulk
ironman spiderman doctorstrange hulk 
가장 긴 이름은 :doctorstrange

컬렉션의 순차 검색을 위한 iterator

Vector, ArrayList, LinkedList, Set과 같이 요소가 순서대로 저장된 컬렉션에서 요소를 순차적으로 검색할 때는 java.util 패키지의 Iterator<E> 인터페이스를 사용하면 편리하다. 여기서 <E>에는 컬렉션의 매개변수와 동일한 타입을 저장해야 한다. 

var v = new Vector<Integer>();
Iterator<Integer> it = v.iterator();

while (it.hasNext()){
	 int n = it.next();
     System.out.println(n);
}
// 차음 it.next()는 v의 첫 번째 요소를 리턴하고, it는 다음 요소를 가리키게 한다.

댓글