[7] 제네릭과 컬렉션

서희찬·2022년 12월 3일
0
post-thumbnail

컬렉션


  • 요소 객체들의 저장소
    => 객체들의 컨테이너
    => 요소의 개수에 따라 크기 자동 조절
    => 요소의 삽입, 삭제에 따른 요소의 위치 자동 이동
  • 고정 크기의 배열을 다루는 어려움 해소!
  • 다양한 객체들의삽입, 삭제, 검색등의 관리가 용이
    하게 만들어주는 것이 컬렉션이다.

컬렉션을 위한 자바 인터페이스와 클래스

컬렉션과 제네릭

  • 컬렉션은 제네릭 기법으로 구현
  • 컬렉션의 요소는 "객체"만 가능!!

제네릭?

특정 타입만 다루지 않고, 여러 종류의 타입으로 변신할 수 있도록 클래스나 메소드를 일반화 시키는 기법

STACK<E>
  • E에 특정 타입으로 구체화
  • 정수만 다루는 스택은 E자리에 Integer..

제네릭 스택 클래스의 JDK매뉴얼

Vector< E >

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

Vecotr < Ineger > 컬렉션 내부 구성

타입 매개 변수 사용하지 않을 경우 경고가 발생한다.

주요 Vector 메소드

vecotr 생성, 삽입, 출력, 삭제

Vector<Integer> v = new Vector<Integer>(7);

v.add(5); //삽입 
v.add(4);
v.add(-1); 

int n = v.size(); // 요소 개수 n = 3
int c = v.capcity(); // 용량 c = 7

v.add(2,100); // 인덱스 2에 삽입, v.size보다 큰 곳에서는 삽입 불가

Integer obj = v.get(1); // 1번째 요소 가져와서 정수로 바꾸기
int i = obj.intValue(); 

v.remove(1); // 1번째 인덱스 삭제
int last = v.lastElement(); // 마지막 요소 가져오기
v.removeAllElements(); // 모든 요소 삭제

컬렉션과 자동 박싱/언박싱

JDK 1.5 이전

  • 기본 데이터 타입 데이터를 Wrapper 클래스를 이용하여 객체로 만들어 사용
 Vector<Integer> v = new Vector<Integer>(); 
 v.add(Integer.valueOf(4));
  • 컬렉션으로부터 요소를 얻어올 때, Wrapper 클래스로 캐스팅 필요
 Integer n = (Integer)v.get(0); 
 int k = n.intValue(); // k = 4

JDK 1.5 이후

  • 자동 박싱/언박싱이 작동하여 기본 타입 값 사용 가능
Vector<Integer> v = new Vector<Integer> ();
v.add(4); // 4 → Integer.valueOf(4)로 자동 박싱
int k = v.get(0); // Integer 타입이 int 타입으로 자동 언박싱, k = 4
  • 제네릭 타입 매개 변수를 기본 타입으로 구체화할수는 없음.
Vector<int> v = new Vector<int> (); // 오류

예제 7-1 : 정수만 다루는 Vector< Ineger > 컬렉션 활용

예제 7-2 : Point 클래스만 다루는 Vector< Point > 컬렉션 활용

컬렉션을 매개변수로 받는 메소드

// Integer 벡터를 매개변수로 받아 원소를 모두 출력하는 printVector() 메소드

public void printVector(Vector<Integer> v){
for(int i=0; i<v.size(); i++) {
	int n = v.get(i); // 벡터의 i 번째 정수
	System.out.println(n); 
    }
}

Vector<Integer> v = new Vector<Integer>();// Integer 벡터 생성
printVector(v); // 메소드 호출

자바의 타입 추론 기능의 진화

// Java 7 이전
Vector<Integer> v = new Vector<Integer>(); 

// java 7 이후
// 컴파일러의 타입 추론 기능 추가 
// 다이아몬드 연산자에 타입 매개변수 생략 
Vector<Integer> v = new Vector<>(); // Java 7부터 추가, 가능

// java 10 이후
// var 키워드 도입 
// 컴파일러의 지역 변수 타입 추론 가능 
var v = new Vector<Integer>(); // Java 10부터 추가, 가능

ArrayList< E >

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

동기화 기능 없는 것이 벡터와의 차이점인것 같다..

내부 구성

주요 메소드

ArrayList 생성, 삽입, 출력, 삭제

ArrayList<String> a = new ArrayList<String>(7);

a.add("Hello"); //삽입 
a.add("hi");
a.add("JAVA"); 

int n = a.size(); // 요소 개수 n = 3
// capcity() method 없음 

v.add(2,"chan"); // 인덱스 "chan"에 삽입, a.size보다 큰 곳에서는 삽입 불가

String str = a.get(1);

a.remove(1); // 1번째 인덱스 삭제

a.clear(); // 모든 요소 삭제

예제 7-3 : 문자열을 입력받아 ArrayList에 저장

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

  • Iterator< E > 인터페이스
    - Vector< E >, ArrayList< E >, LinkedList< E >가 상속받는 인터페이스
    => 리스트 구조의 컬렉션에서 요소의 순차 검색을 위한 메소드 포함
  • Iterator< E > 인터페이스 메소드
boolean hasNext() // 방문할 요소가 남아있으면 return true 
E next() // return next elemenet 
void removve() // last return element delete
  • iterator() method : Iterator 객체 반환
    => Iterator 객체를 이용하여 index 없이 순차 검색 가능
Vector<Integer> v = new Vector<Integer>(); // 벡터 생성 
Iterator<Integer> it = v.iterator();  // v의 iterator it생성 
while(it.hasNext()) { // 
모든 요소 방문
int n = it.next(); // 다음 요소 리턴
... }

예제 7-4 : Iterator를 이용하여 Vector의 모든 요소를 출력하고 합 구하기

HashMap<K,V>

  • 키(key)와 값(value)의 쌍으로 구성되는 요소를 다루는 컬렉션
    => java.util.HashMap
    => K는 키로 사용할 요소의 타입,V는 값으로 사용할 요소의 타입지정
    => 키와 값이 한 쌍으로 삽입
    => 키는 해시맵에 삽입되는 위치 결정에 사용
    => 값을 검색하기 위해서는 반드시 키 이용
  • 삽입, 삭제, 검색이 빠른 특징
    => 요소 삽입 : put() 메소드
    => 요소 검색 : get() 메소드
  • 예) HashMap<String, String> 생성, 요소 삽입, 요소 검색
HashMap<String, String> h = new HashMap<String, String>(); 
h.put("apple", "사과"); // "apple" 키와 "사과" 값의 쌍을 해시맵에 삽입
String kor = h.get("apple"); // "apple" 키로 값 검색. kor는 "사과“

내부구성

주요 메소드

HashMap 생성, 키,값 삽입, .. 읽기, 삭제 등등..

HashMap<Stirng, String> h = new HashMap<String, String>(); // 해시맵 생성 

h.put("baby","아기"); //삽입 
h.put("love","사랑");
h.put("apple","사과");

String kor = h.get("love"); //key로 값 읽기 

h.remove("apple"); // key로 요소 삭제 

int n = h.size(); // 요소 개수 n = 2

예제 7-5 : HashMap을 이용하여 (영어, 한글) 단어 쌍의 저장 검색

예제 7-6 : HashMap을 이용하여 자바 과목의 이름과 점수 관리

예제 7-7 HashMap에 객체 저장, 학생 정보 관리

LinkedList< E >

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

내부구성

Collections 클래스 활용

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

예제 7-8 : Collections 클래스의 활용

제네릭 만들기

  • 제네릭 클래스와 인터페이스
  • 클래스나 인터페이스 선언부에 일반화된 타입 추가
public class MyClass<T> { 
	T val;
	void set(T a) {
	    val=a; // T type value "a" => val save 
    } 
	T get() {
		return val; // return T type value
	}
}
  • 제네릭 클래스 레퍼런스 변수 선언
MyClass<String> s;
List<Integer> li;
Vector<String> vs;

제네릭 객체 생성 - 구체화

  • 제네릭 타입의 클래스에 구체적인 타입을 대입하여 객체 생성
  • 컴파일러에 의해 이루어짐
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 출력
  • 구체화된 MyClass< Stirnng >의 소스 코드

구체화 오류

타입 매개 변수에 기본 타입은 사용할 수 없음

타입 매개 변수

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

예제 7-9 : 제네릭 스택 만들기

제네릭과 배열

제네릭에서 배열의 제한

  • 제네릭 클래스 또는 인터페이스의 배열을 헝ㅇ하지 않음
  • 제네릭 타입의 배열도 허용되지 않음
  • 타입 매개변수의 배열에 레퍼런스는 허용

제네릭 메소드

  • 제네릭 메소드 선언 가능
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로 유추함

예제 7-10 : 스택의 내용을 반대로 만드는 제네 릭 메소드 만들기

제네릭의 장점

  • 컴파일 시에 타입이 결정되어 보다 안전한 프로그래밍 가능
  • 런타임 타입 충돌 문제 방지
  • classCastException 방지
profile
Developing For Our Lives, 세상에 기여하는 삶을 살고자 개발하고 있습니다

0개의 댓글