[Java] 컬렉션 프레임워크_Map 컬렉션

Devlog·2024년 4월 3일

Java

목록 보기
40/41

✔️ Map 컬렉션

: 키(key)와 값(value)으로 구성된 Map.Entry 객체를 저장하는 구조를 가지고 있음

: Entry는 Map 인터페이스 내부에 선언된 중첩 인터페이스
여기서 키와 값은 모두 객체

: 키는 중복 저장될 수 없지만 값은 중복 저장될 수 있음

만약 기존에 저장된 키와 동일한 키로 값을 저장하면
기존의 값은 없어지고 새로운 값으로 대체됨

: Map 컬렉션에는
HashMap, Hashtable, LinkedHashMap, Properties, TreeMap 등이 있음

  • Map 컬렉션에서 공통적으로 사용 가능한 Map 인터페이스의 메소드

: 키로 객체들을 관리히기 때문에 키를 매개값으로 갖는 메소드가 많음

: 메소드의 매개 변수 타입과 리턴 타입에 K와 V라는 타입 파라미터는
저장되는 키와 객체의 타입을 Map 컬렉션을 생성할 때 결정하라는 뜻

ex)
키 타입이 String, 값 타입이 Integer인 Map 컬렉션을 생성하고,
put()메소드로 키와 값을 저장함

그리고 키로 값을 얻거나 제거하기 위해
get()과 remove() 메소드를 사용함

Map<String, Integer> map = ···;
map.put("홍길동", 30);
int score = map.get("홍길동");
map.remove("홍길동");

: Map<String, Integer>로 map 변수를 선언
이것은 Map 컬렉션에 저장되는 키 객체는 String 타입으로,
값 객체는 Integer 타입으로 하겠다는 뜻

따라서 K 타입 파라미터는 String이 되고,
V 타입 파라미터는 Integer가 되는 것

그래서 put() 메소드의 첫 번째 매개 값은 문자열이고,
두 번째 매개값은 30이 포장된 Integer 객체(자동 박싱)가 됨

- 저장된 전체 객체를 대상으로 하나씩 얻고 싶을 경우
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를 하나씩 얻고
getKey()와 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

: Map 인터페이스를 구현한 대표적은 Map 컬렉션

: HashMap의 키로 사용할 객체는
hashCode()와 equals() 메소드를 재정의해서
동등 객체가 될 조건을 정해야함

: 객체가 달라도 동등 객체라면 같은 키로 간주하고
중복 저장되지 않도록 하기 위함

: 동등 객체의 조건은 hashCode()의 리턴값이 같아야 하고,
equalsd() 메소드가 true를 리턴해야함

: 주로 키 타입은 String을 많이 사용하는데,
String은 문자열이 같을 경우 동등 객체가 될 수 있도록
hashCode()와 equals() 메소드가 재정의되어 있음

- HashMap 생성

Map<K, V> amp = new HasMap<K, V>();

키 타입과 값 타입을 타입 파라미터로 주고 기본 생성자를 호출하면됨

: 키와 값의 타입은
기본 타입(byte, short, int, float, double, boolean, char)을 사용할 수 없고
클래스 및 인터페이스 타입만 사용 가능

ex) 키로 String 타입을 사용하고 값으로 Integer 타입을 사용시 HashMap 생성
Map<String, Integer> map = new HashMap<String, Integer>();
Map<String, Integer> map = new HashMap<>();
👩‍💻 이름을 키로 점수를 값으로 저장하기
import java.util.*;

public class HashMapExample {

	public static void main(String[] args) {
		//Map 컬렉션 생성
		Map<String, Integer> map = new HashMap<String, Integer>();
		
		//객체 저장
		//홍길동2는 키가 같기 떄문에 마지막 저장 값으로 대체
		map.put("홍길동1", 85);
		map.put("홍길동2", 90);
		map.put("홍길동3", 80);
		map.put("홍길동2", 95);
		System.out.println("총 Entry 수: " + map.size());
		
		//객체 찾기
		//이름(키)으로 점수(값)를 검색
		System.out.println("\t홍길동2: " + map.get("홍길동2"));
		System.out.println();
		
		//객체를 하나씩 처리
		Set<String> keySet = map.keySet();
		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("홍길동2");
		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
	홍길동2: 95

	홍길동2: 95
	홍길동3: 80
	홍길동1: 85

총 Entry 수: 2
	홍길동3: 80
	홍길동1: 85

총 Entry 수: 0

// 키로 사용할 객체
// hashCode()와 equals() 재정의
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) {
		if(obj instanceof Student) {
			Student student = (Student) obj;
			return (sno == student.sno) && (name.equals(student.name));
		} else {
			return false;
		}
	}
	
	public int hashCode() {
		return sno + name.hashCode();
	}
}

// 학번과 이름이 동일한 경우 같은 키로 인식
public class HashMapExample2 {
	public static void main(String[] args) {
		Map<Student, Integer> map = new HashMap<Student, Integer>();
		
		map.put(new Student(1, "홍길동"), 95);
		map.put(new Student(1, "홍길동"), 95);
		
		System.out.println("총 Entry 수: " + map.size());
	}
}

💻 결과
총 Entry 수: 1

✔️ Hashtable

: HashMap과 동일한 내부 구조를 가짐
: 키로 사용할 객체는 hashCode()와 equals() 메소드를
재정의해서 동등 객체가 될 조건
을 정해야함

: HashMap과 차이점
Hashtable은 동기화된 메소드로 구성되어 있기 때문에
멀티 스레드가 동시에 Hashtable의 메소드들을 실행할 수 없고,
하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있다는 것

그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있기 때문에
Hashtable은 스레드에 안전함

- 생성방법

Map<K, V> map = new Hashtable<K, V>();

-방법

ex) 키로 String 타입을 사용하고, 값으로 Integer 타입을 사용하는 Hashtable 생성
Map<String, Integer> map = new Hashtable<String, Integer>();
Map<String, Integer> map = new Hashtable<>();
👩‍💻 아이디와 비밀번호 검사하기
import java.util.*;

public class HashTableExample {
	public static void main(String[] args) {
		Map<String, String> map = new Hashtable<String, String>();
		
		map.put("spring", "12");
		map.put("summer", "123");
		map.put("fall", "1234");
		map.put("winter", "12345");
		
		Scanner scanner = new Scanner(System.in);
		
		while(true) {
			System.out.println("아이디와 비밀번호르 입력해주세요.");
			System.out.println("아이디: ");
			String id = scanner.nextLine();
			
			System.out.println("비밀번호: ");
			String password = scanner.nextLine();
			System.out.println();
			
			if(map.containsKey(id)) {
				if(map.get(id).equals(password)) {
					System.out.println("로그인되었습니다.");
					break;
				}else {
					System.out.println("비밀번호가 일치하지 않습니다.");
				}
			} else {
				System.out.println("입력하신 아이디가 존재하지 않습니다.");
			}
		}
	}
}

💻 결과
아이디와 비밀번호르 입력해주세요.
아이디: 
summer
비밀번호: 
123

로그인되었습니다.

0개의 댓글