JUINTINATION

제네릭과 컬렉션 본문

자바프로그래밍및실습

제네릭과 컬렉션

DEOKJAE KWON 2022. 12. 22. 16:56
반응형

컬렉션

  • 요소(element) 객체들의 저장소
    • 객체들의 컨테이너라고도 불림
    • 요소의 개수에 따라 크기 자동 조절
    • 요소의 삽입, 삭제에 따른 요소의 위치 자동 이동
  • 고정 크기의 배열을 다루는 어려움 해소
  • 다양한 객체들의 삽입, 삭제, 검색 등의 관리 용이

  • 컬렉션은 제네릭(generics) 기법으로 구현됨
  • 컬렉션의 요소는 객체만 가능
    • 기본적으로 int, char, double 등의 기본 타입 사용 불가
      • JDK 1.5부터 자동 박싱/언박싱으로 기본 타입 값을 객체로 자동 변환

 

제네릭

  • 특정 타입만 다루지 않고, 여러 종류의 타입으로 변신할 수 있도록 클래스나 메소드를 일반화시키는 기법
    • <E>, <K>, <V> : 타입 매개 변수
      • 요소 타입을 일반화한 타입
  • 제네릭 클래스 사례
    • 제네릭 스택 : Stack<E>
      • E에 특정 타입으로 구체화
      • 정수만 다루는 스택 Stack<Integer>
      • 문자열만 다루는 스택 Stack<String>

Vector<E>

  • java.util.Vector
    • <E>에서 E 대신 요소로 사용할 특정 타입으로 구체화
  • 여러 객체들을 삽입, 삭제, 검색하는 컨테이너 클래스
    • 배열의 길이 제한 극복
    • 원소의 개수가 넘쳐나면 자동으로 길이 조절
  • Vector에 삽입 가능한  것
    • 객체, null
    • 기본 타입은 Wrapper 객체로 만들어 저장
  • Vector에 객체 삽입
    • 벡터의 맨 뒤에 객체 추가
    • 벡터 중간에 객체 삽입
  • Vector에서 객체 삭제
    • 임의의 위치에 있는 객체 삭제 가능 : 객체 삭제 후 자동 자리 이동

Vector<Integer> v = new Vector<Integer>();
v.add(4); // 4 → Integer.valueOf(4)로 자동 박싱
int k = v.get(0); // Integer 타입이 int 타입으로 자동 언박싱, k = 4

ArrayList<E>

  • java.util.ArrayList, 가변 크기 배열을 구현한 클래스
    • <E>에서 E 대신 요소로 사용할 특정 타입으로 구체화
  • ArrayList에 삽입 가능한  것
    • 객체, null
    • 기본 타입은 박싱/언박싱으로 Wrapper 객체로 만들어 저장
  • ArrayList에 객체 삽입/삭제
    • 리스트의 맨 뒤에 객체 추가
    • 리스트의 중간에 객체 삽입
    • 임의의 위치에 있는 객체 삭제 가능
  • 벡터와 달리 스레드 동기화 기능 없음
    • 다수 스레드가 동시에 ArrayList에 접근할 때 동기화되지 않음
    • 개발자가 스레드 동기화 코드 작성

ArrayList<Integer> a = new ArrayList<Integer>();
a.add(4); // 4 → Integer.valueOf(4)로 자동 박싱
int k = a.get(0); // Integer 타입이 int 타입으로 자동 언박싱, k = 4

 

LinkedList<E>

  • java.util.LinkedList
    • E에 요소로 사용할 타입 지정하여 구체와
  • List 인터페이스를 구현한 컬렉션 클래스
  • Vector, ArrayList 클래스와 매우 유사하게 작동
  • 요소 객체들은 양방향으로 연결되어 관리됨
    • 요소 객체는 맨 앞, 맨 뒤에 추가 가능
    • 인덱스를 이용하여 중간에 삽입 가능
    • 맨 앞이나 맨 뒤에 요소를 추가하거나 삭제할 수 있어 스택이나 큐로 사용 가능

HashMap<K, V>

  •  java.util.HashMap
    • 키(key)와 값(value)의 쌍으로 구성되는 요소를 다루는 컬렉션
    • K는 키로 사용할 요소의 타입, V는 값으로 사용할 요소의 타입 지정
    • 키와 값이 한 쌍으로 삽입
      • 키는 해시맵에 삽입되는 위치 결정에 사용
      • 값을 검색하기 위해서는 반드시 키 이용
  • 삽입, 삭제, 검색이 빠르다는 특징
    • 요소 삽입 : put() 메소드
    • 요소 검색 : get() 메소드

Iterator<E>

HashMap<String, String> map = new HashMap<>();
HashSet<String> set = new HashSet<>(cities.keySet());
Iterator<String> it = keys.iterator();
while (it.hasNext()) {
    String key = it.next();
    String val = map.get(key);
}
 

Collections 클래스

  • java.util.Collections
    • 컬렉션에 대해 연산을 수행하고 결과로 컬렉션 리턴
    • 모든 메소드는 static 타입
  • 주요 메소드
    • 컬렉션에 포함된 요소들을 소팅하는 sort() 메소드
    • 요소의 순서를 반대로 하는 reverse() 메소드
    • 요소들의 최대, 최솟값을 찾아내는 max(), min() 메소드
    • 특정 값을 검색하는 binarySearch() 메소드

제네릭 클래스 만들기

  • 클래스나 인터페이스 선언부에 일반화된 타입 추가
public class MyClass<T> {
    T val;
    void set(T a) {
        val = a; 
    }
    T get() {
        return val; 
    }
}
  • 제네릭 클래스 레퍼런스 변수 선언
MyClass<Double> d;
  • 구체화
    • 제네릭 타입의 클래스에 구체적인 타입을 대입하여 객체 생성
    • 컴파일러에 의해 이루어짐
    • 타입 매개 변수에 기본 타입은 사용할 수 없음
MyClass<String> s = new MyClass<String>(); // 제네릭 타입 T에 String 지정
s.set("hello");
System.out.println(s.get()); // "hello" 출력

MyClass<Integer> n = new MyClass<Integer>(); // 제네릭 타입 T에 Integer 지정
n.set(5);
System.out.println(n.get()); // 숫자 5 출력

타입 매개 변수

  • ‘<‘과 ‘>’사이에 하나의 대문자를 타입 매개변수로 사용
  • 많이 사용하는 타입 매개 변수 문자
    • E : Element를 의미하며 컬렉션에서 요소를 표시할 때 많이 사용한다.
    • T : Type을 의미한다.
    • V : Value를 의미한다.
    • K : Key를 의미
  • 타입 매개변수가 나타내는 타입의 객체 생성 불가
    • ex) T a = new T();
  • 타입 매개변수는 나중에 실제 타입으로 구체화
  • 어떤 문자도 매개 변수로 사용 가능

MyStack 만들기

  • 제네릭에서 배열의 제한
    • 제네릭 클래스 또는 인터페이스의 배열을 허용하지 않음
      • GStack<Integer>[] gs = new GStack<Integer>[10];
    • 제네릭 타입의 배열도 허용되지 않음
      • T[] a = new T[10]; 
      • 아래 예제에서는 Object 타입으로 배열 생성 후 실제 사용할 때 타입 캐스팅
        • return (T)stck[tos]; // 타입 매개 변수 T타입으로 캐스팅
    • 타입 매개변수의 배열에 레퍼런스는 허용
      • public void myArray(T[] a) {....}
  • 제네릭 메소드 선언 가능
class GenericMethodEx {
	static <T> void toStack(T[] a, GStack<T> gs) {
		for (int i = 0; i < a.length; i++) {
			gs.push(a[i]);
		}
	}
}
  • 제네릭 메소드를 호출할 때는 컴파일러가 메소드의 인자를 통해 이미 타입을 알고 있으므로 타입을 명시할 필요 X
Object[] oArray = new Object[100];
GStack<Object> objectStack = new GStack<Object>();
GenericMethodEx.toStack(oArray, objectStack); // 타입 매개변수 T를 Object로 유추함
class GStack<T> {
    int tos;
    Object[] stck;
    public GStack() {
        tos = 0;
        stck = new Object[10];
    }
    public void push(T item) {
        if (tos == 10) return;
        stck[tos++] = item;
    }
    public T pop() {
        if (tos == 0) return null;
        return (T)stck[--tos];
    }
}

class GenericMethodEx {
    public static <T> GStack<T> reverse(GStack<T> a) {
        GStack<T> s = new GStack<T>();
        while (true) {
            T tmp = a.pop();
            if (tmp == null) break;
            s.push(tmp);
        }
        return s;
    }
    static <T> void toStack(T[] a, GStack<T> gs) {
        for (T ai : a) {
            gs.push(ai);
        }
    }
}

public class MyStack extends GenericMethodEx {
    public static void main(String[] args) {
        GStack<Integer> intStack = new GStack<Integer>();
        for (int i = 0; i < 10; i++) {
            intStack.push(i);
        }
        for (Object e : intStack.stck) {
            System.out.print(e + " ");
        }
        System.out.println();
        intStack = reverse(intStack);
        for (Object e : intStack.stck) {
            System.out.print(e + " ");
        }
    }
}

제네릭의 장점

  • 컴파일 시에 타입이 결정되어 보다 안전한 프로그래밍 가능
  • 런타임 타입 충돌 문제 방지
  • ClassCastException 방지

내 생각

수업 시간에 위의 내용을 배우기 전에 코딩하면서 당연하다고 생각하며 넘어갔던 내용이었습니다. 그저 배열의 크기가 한정되어 있지 않기 때문에 사용하던 것들이었는데 추후에 프로젝트를 진행하면서 여러 가지 Exception을 방지할 수 있고 보다 안전한 프로그래밍이 가능하다는 장점이 있으며 원한다면 저만의 제네릭 클래스를 만들 수 있다는 사실이 놀라웠습니다.

728x90

'자바프로그래밍및실습' 카테고리의 다른 글

JDBC 프로그래밍  (0) 2023.01.08
소켓 프로그래밍  (0) 2023.01.06
스레드와 멀티태스킹  (0) 2023.01.03
Comments