[Java 25] 자바 - 컬렉션 프레임워크 (1)

학습목표

  1. 컬렉션 프레임워크의 기본적인 개념을 이해한다.
  2. List, Set, Map의 사용법을 알고있다.

컬렉션 프레임워크 소개

Collections Framework Class diagram
출처: 생활코딩

자료구조를 바탕으로 객체들을 효율적으로 추가, 삭제, 검색할 수 있도록 java.util 패키지에 컬렉션과 관련된 인터페이스와 클래스들을 포함시켜 놓았습니다. 이를 총칭해 컬렉션 프레임워크라고 합니다.

컬렉션

인터페이스 분류 특징 구현 클래스  
collection List - 순서를 유지하고 저장 - 중복 저장가능 ArrayList, Vetor, LinkedList
collection Set - 순서를 유지하지 앟고 저장 - 중복 저장 안됨 HashSet, TreeSet
Map - 키와 값의 쌍으로 저장 - 키는 중복 저장 안됨 HashMap, Hashtable, TreeMap, Properties  

List 컬렉션

  • 객체를 일렬로 늘어놓은 구조
  • 객체를 인덱스로 관리하기 때문에 객체를 저장하면 자동 인덱스가 부여되고 인덱스를 통해 검색, 삭제가 가능
  • List 컬렉션은 객체 자체를 저장하는 것이 아니라 객체의 번지를 참조
  • 동일한 객체를 중복 저장이 가능한데, 이 경우 동일한 번지가 참조( null도 저장 가능 )

ArrayList

  • 생성할 때 크기가 고정되는 배열과 달리, ArrayList는 저장 용량을 초과한 객체들이 들어오면 자동적으로 저장용량 늘어남
  • ArrayList에 객체를 추가하면 인덱스 0부터 차례대로 저장
  • 특정 인덱스의 객체 제거하면 이후의 모든 인덱스가 1씩 당겨지고 특정 인덱스에 객체 삽입하면 이후의 모든 인덱스가 1씩 밀린다.
List<String> list = new ArrayList<String>();	//컬렉션 생성
list.add("홍길동"); 	//컬렉션에 객체를 추가
String name = list.get(0);	//컬렉션에서 객체 검색, 홍길동 바로 얻음

예제 1

import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		
		//String 객체를 저장
		list.add("Java");
		list.add("JVM");
		list.add("abcd");
		list.add("ABCD");
				
		//저장된 총 객체수 반환
		int size = list.size();
		System.out.println("총 객체수 : " + size);
		System.out.println();
		
		//2번 인덱스의 객체 얻기
		String skill = list.get(2);
		System.out.println("2 : " + skill);
		System.out.println();
		
		// 저장된 객체 수만큼 루핑
		for(int i =0; i <list.size(); i++) {
			String str = list.get(i);
			System.out.println(i + ":" + str);
		}
		System.out.println();
		
		list.remove(2);	// 2번 인덱스 객체 삭제
		list.remove(2); // 2번 인덱스 객체 삭제
		list.remove("abcd");
		
		// 저장된 객체 수만큼 루핑
		for(int i =0; i <list.size(); i++) {
			String str = list.get(i);
			System.out.println(i + ":" + str);
		}
	}
}

실행결과

총 객체수 : 4

2 : abcd

0:Java
1:JVM
2:abcd
3:ABCD

0:Java
1:JVM

예제 2

import java.util.Arrays;
import java.util.List;

public class ArraysAsListExample {
	public static void main(String[] args) {
		List<String> list1 = Arrays.asList("홍길동", "김길동", "자바"); //왜 new 안해줌?
		for(String name: list1) {
			System.out.println(name);
		}
		
		List<Integer> list2 = Arrays.asList(1,2,3);
		for(int value : list2) {
			System.out.println(value);
		}
	}
}

실행결과

홍길동
김길동
자바
1
2
3

Set 컬렉션

  • List 컬렉션은 저장 순서를 유지하지만, Set 컬렉션은 저장 순서가 유지되지 않음
  • 수학의 집합이라고 생각하면 된다.
Set<String> set = ...;
set.add("홍길동");	//객체 추가
set.add("김길동");
set.remove("홍길동");	//객체 삭제
  • Set 컬렉션은 인덱스로 객체를 검색해서 가져오는 메소드는 없다. 대신 전체 객체를 대상으로 한번씩 반복해서 가죠오는 반복자(Iterator)를 제공한다.
Set<String> set = ...;
Iterator<String> iterator = set.iterator();
  • 다음은 Iterator 인터페이스에 선언된 메소드들이다.
리턴 타입 메소드명 설명
boolean hasNext() 가져올 객채가 있으면 true 리턴하고 없으면 false 리턴
E next() 컬렉션에서 하나의 객체를 가져온다
void remove() Set 컬렉션에서 객체를 가져온다
  • Iterator에서 하나의 객체를 가져올 때는 next() 메소드를 사용한다. next() 메소드를 사용하기 전에 먼저 가져올 개체가 있는지 확인
  • hasNext() 메소드는 가져올 객체가 있으면 true 리턴하고 더 이상 가져올 객체가 없으면 false를 리턴
  • 따라서 true가 리턴될 때 next() 메소드를 사용해야 한다.
Set<String> set = ...;		
	Iterator<String> iterator = set.iterator();
	// 저장된 객체 수만큼 루핑한다
	while (iterator.hasNext()) {
		// String 객체 하나를 가져옴
		String str = iterator.next();
	}
  • Iterator 사용하지 않더라도 향상된 for문을 이용해서 전체 객체 대상으로 반복이 가능
Set<String> set = ...;
// 저장된 객체 수만큼 루핑한다
for(String str : set) {
}
  • remove() 메소드를 통한 객체 제거 가능
while(iterator.hasNext()) {
	String str = iterator.next();
	if(str.equals("홍길동")) {
		iterator.remove();
	}
}

HashSet

  • HashSet 생성을 위한 기본 생성자
Set<E> set = new HashSet<E>();
  • HashSet은 객체들을 순서 없이 저장하고 동일한 객체는 중복 저장하지 않는다.

hashset

public class HashSetExample {
public static void main(String[] args) {
	Set<String> set = new HashSet<String>();

	set.add("Java");
	set.add("JDBC");
	set.add("Servlet/JSP");
	set.add("Java");	// "Java"는 한번만 저장됨
	set.add("abcde");

	int size = set.size();	// 저장된 객체 수 얻기
	System.out.println("총 객체수 : " + size);

	Iterator<String> iterator = set.iterator(); // 반복자 얻기
	// 객체 수만큼 루핑
	while (iterator.hasNext()) {
		String element = iterator.next();	// 한개의 객체를 가져온다
		System.out.println("\t" + element);
	}
	// 객체 삭제
	set.remove("JDBC");
	set.remove("abcde");
	
	System.out.println("총 객체수: " + set.size());
	
	iterator = set.iterator();	// 반복자 얻기
	// 객체 수만큼 루핑
	while(iterator.hasNext()) {
		String element = iterator.next();
		System.out.println("\t" + element);
	}
	set.clear();	// 모든 객체 제거
	if(set.isEmpty()) { System.out.println("비어 있음"); }
}
}

실행결과

총 객체수 : 4
	Java
	abcde
	JDBC
	Servlet/JSP
총 객체수: 2
	Java
	Servlet/JSP
비어 있음

예제 2 사용자 정의 클래스인 Member를 만들고 hashCode()와 equals() 메소드를 오버라이딩하였다. 이를 통해 인스턴스가 달라도 이름과 나이가 동일하면 동일한 객체로 간주하여 중복 저장을 방지한다.

public class Member {
	public String name;
	public int age;

	public Member(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public boolean equals(Object obj) {	//name과 age 값이 같으면 true 리턴
		if (obj instanceof Member) {
			Member member = (Member) obj;
			return member.name.equals(name) && (member.age == age);
		} else {
			return false;
		}
	}

	@Override
	public int hashCode() {		//name과 age 값이 같으면 동일한 hashCode 리턴
		return name.hashCode() + age;
	}
}
import java.util.*;

public class HashSetExample2 {
	public static void main(String[] args) {
		Set<Member> set = new HashSet<Member>();

		//인스턴스는 다르지만 내부 데이터가 동일하므로 객체 1개만 저장
		set.add(new Member("홍길동", 20));
		set.add(new Member("홍길동", 20));	

		System.out.println("총 객체수 : " + set.size());
	}
}

실행결과

총 객체수 : 1

Map 컬렉션

  • 키(key)와 값(value)으로 구성된 Entry 객체를 저장하는 구조
  • 키와 값은 모두 객체이다.
  • 키는 중복 저장될 수 없고, 값은 중복 저장이 가능하다.
  • 만약 기존에 저장된 키와 동일한 키로 값을 저장하면 기존의 값은 없어지고 새로운 값으로 대치된다.
Map<String, Integer> map = ~;
map.put("홍길동", 30);	//객체 추가
int score = map.get("김길동");  //객체 찾기
map.remove("홍길동");	//객체 삭제
  • 키를 알고 있다면 get() 메소드로 간단하게 객체를 찾아오면 되지만, 저장되니 객체를 대상으로 하나씩 얻고 싶은 경우에는 두가지 방법을 사용할 수 있다.

방법 1

keySet() 메소드로 모든 키를 Set 컬렉션으로 얻은 다음, 반복자를 통해 키를 하나씩 얻고 get() 메소드를 통해 값을 얻는다.

Map<K, V> map = ~;
Set<K> keyset = map.keySet();		
Iterator<K> keyIterator = keySet.iterator();
	while (keyiterator.hasNext()) {
		K key = keyIterator.next();
		v value = map.get(key);
	}

방법 2

entrySet() 메소드로 모든 Map.Entry를 Set 컬렉션으로 얻은 다음, 반복자를 통해 Map.Entry를 하나씩 얻고 getValue() 메소드를 이용해 키와 값을 얻으면 된다.

Set<Map.Entry<K, V>> entrySet = map.entrySet();
Iterator<Map.Entry<K, V>> entryIterator = entrySet.iterator();
while(entryIterator.hasNext()) {
	Map.Entry<K, V> entry = entryIterator.next();
	K key = entry.getKey();
	V value = entry.getValue();
}

HashMap

  • HashMap의 키로 사용할 객체는 hasCode()와 equals() 메소드를 재정의해서 동등 객체가 될 조건을 정해야 한다.
  • 동등 개체, 즉 동일한 키가 될 조건은 hashCode()의 리턴값이 같아야 하고, equals() 메소드가 true를 리턴해야 한다.

hashmap

  • 주로 키 타입은 String을 많이 사용하는데, String은 문자열이 같을 경우 동등 객체가 될 수 있도록 hashCode()와 equals() 메소드가 재정의되어 있다
  • HashMap을 생성하기 위해서는 키 타입과 값 타입을 파라미터로 주고 기본 생성자를 호출하면 된다.
Map<K, V> map = new HashMap<K, V>(); //K: 키 타입, V: 값 타입
  • 키와 값의 타입은 기본타입을 사용할 수 없고 클래스 및 인터페이스 타입만 가능
  • 키로 String 타입을 사용하고 값으로 Integer 타입을 사용하는 HashMap은 다음과 같이 생성된다.
Map<String, Integer> map = new HashMap<String, Integer>();

예제 1

public class HashMapExample {
public static void main(String[] args) {
	Map<String, Integer> map = new HashMap<String, Integer>();

	map.put("홍길동", 85);
	map.put("박길동", 90);
	map.put("김길동", 80);
	map.put("홍길동", 95);	// "홍길동" 키가 같기 떄문에 제일 마지막에 저장한 값으로 대치
	System.out.println("총 Entry 수 : " + map.size());

	// 객체 찾기
	System.out.println("\t홍길동 : " + map.get("홍길동")); //이름(키)으로 점수(값)를 검색
	System.out.println();

	// 객체를 하나씩 처리
	Set<String> keySet = map.keySet();	//Key Set 얻기
	Iterator<String> keyIterator = keySet.iterator();
	while (keyIterator.hasNext()) {
		String key = keyIterator.next();
		Integer value = map.get(key);
		System.out.println("\t" + key + " : " + value);
	}

	System.out.println();

	// 객체 삭제
	map.remove("홍길동");
	System.out.println("총 Entry 수 :" + map.size());

	// 객체 하나씩 처리
	Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
	Iterator<Map.Entry<String, Integer>> entryIterator = entrySet.iterator();

	while (entryIterator.hasNext()) {
		Map.Entry<String, Integer> entry = entryIterator.next();
		String key = entry.getKey();
		Integer value = entry.getValue();
		System.out.println("\t" + key + " : " + value);
	}
	System.out.println();

	map.clear();
	System.out.println("총 entry 수: " + map.size());
}
}

실행결과

총 Entry 수 : 3
	홍길동 : 95

	박길동 : 90
	김길동 : 80
	홍길동 : 95

총 Entry 수 :2
	박길동 : 90
	김길동 : 80

총 entry 수: 0

예제 2

class Student {
	public int sno;
	public String name;

	public Student(int sno, String name) {
		this.sno = sno;
		this.name = name;
	}

	public boolean equals(Object obj) {	//학번과 이름이 동일할 경우 true 리턴
		if (obj instanceof Student) {
			Student student = (Student) obj;
			return (sno == student.sno) && (name.contentEquals(student.name));
		} else {
			return false;
		}
	}
	// 학번과 이름이 같다면 동일한 값을 리턴
	public int hashCode() {
		return sno + name.hashCode();
	}
}
public class HashMapExample2 {
public static void main(String[] args) {
	Map<String, Integer> map = new HashMap<String, Integer>();
	
	//학번과 이름이 동일한 경우 같은 키로 인식
	map.put("홍길동", 95);
	map.put("홍길동", 95);
	System.out.println("총 Entry 수 : " + map.size());	
	}
}

태그:

카테고리:

업데이트:

댓글남기기