Java :: Collection :: 1.10 HashMap

김병철·2022년 9월 7일
0

Java

목록 보기
7/20

Java의 정석 3판을 보며 공부한 내용을 정리하였습니다.
남궁성님께 많이 배우고 있습니다.

1.10 HashMap과 HashTable

HashTable과 HAshMap의 관계는 Vector와 ArrayList의 관계와 같다!

Vector를 예전에 많이 썼고 앞으로는 ArrayList를 사용하는게 좋은 것처럼.

HashTable보다 HashMap을 사용하는 것이 좋다.

HashMap은 Map을 구현했으므로 Map의 특징을 갖고 있다.

  • Key는 유일해야 한다.

  • Value는 중복을 허용한다.

  • Key와 Value를 묶어서 하나의 데이터로 저장

  • Hashing을 사용하므로 많은 양의 데이터를 검색하는데 뛰어난 성능을 보인다.

다음은 HshMap이 데이터를 저장하는 실제 소스의 일부이다.

public class HashMap extends AbstractMap implements Map, Cloneable, Serializable
{
	transient Entry[] table;
    	...
    static class Entry implements Map.Entry {
    	final Object key;
        Object value;
        	...
    }
}

HashMap은 내부에 Entry라는 내부 클래스를 정의한다.

이것은 무결성적인 측면에서 더 바람직하다.

Entry[] table;
class Entry {
	Object key;
    Object value;
}

HashMap은 Key와 Value를 각각 Object 타입으로 저장해서 어떤 객체도 저장할 수 있지만 Key는 주로 String을 대문자 또는 소문자로 통일해서 사용한다.


HashMap의 생성자와 메서드

  • HashMap()
    -> HashMap객체를 생성
  • HashMap(int initialCapacity)
    -> 지정된 값을 초기용량으로 하는 HashMap 객체를 생성
  • HashMap(int initialCapacity, float loadFactor)
    -> 지정된 초기용량과 load factor의 HashMap객체를 생성
  • HashMap(Map m)
    -> 지정된 Map의 모든 요소를 포함하는 HashMap을 생성
  • void clear()
    -> HashMap에 저장된 모든 객체를 제거
  • Object clone()
    -> 현재 HashMap을 복제해서 반환
  • boolean containsKey(Object key)
    -> HashMap에 지정된 key가 포함되어있는지 알려줌.(포함되면 true)
  • boolean containsValue(Object value)
    -> HashMap에 지정된 value가 포함되어있는지 알려줌.(포함되면 true)
  • Set entrySet()
    -> HashMap에 저장된 키와 값을 엔트리(키와 값의 결합)의 형태로 Set에 저장해서 반환
  • Object get(Object key)
    -> 지정된 key의 값(객체)을 반환. 못찾으면 null반환
  • Object getOfDefault(Object key, Object defaultValue)
    -> 지정된 key의 값(객체)을 반환. 키를 못찾으면, 기본값으로 지정된 객체를 반환
  • boolean isEmpty()
    -> HashMap이 비어있는지 알려줌
  • Set keySet()
    -> HaspMap에 저장된 모든 키가 저장된 Set을 반환
  • Object put(Object key, Object value)
    -> 지정된 키와 값을 HashMap에 저장
  • void putAll(Map m)
    -> Map에 저장된 모든 요소를 HashMap에 저장
  • Object remove(Object key)
    -> HAshMap에서 지정된 키로 저장된 값(객체) 제거
  • Object replace(Object key, Object value)
    -> 지정된 키의 값을 지정된 객체(value)로 대체
  • boolean replace(Object key, Object oldValue, Object newValue)
    -> 지정된 키와 객체(oldValue)가 모두 일치하는 경우에만 새로운 객체(newValue)로 대체
  • int size()
    -> HashMap에 저장된 요소의 개수 반환
  • Collection values()
    -> HashMap에 저장된 모든 값을 컬렉션의 형태로 반환

HashMap에 ID와 비밀번호 저장 후 비교하는 예제

public static void main(String[] args) {
	HashMap map = new HashMap();
	map.put("myId",  "1234");
	map.put("asdf",  "1111");
	map.put("asdf",  "1234");
		
	Scanner s = new Scanner(System.in);
		
	while(true) {
		System.out.println("id와 password입력  ");
		System.out.print("id 입력 : ");
		String id = s.nextLine().trim();
			
		System.out.print("password : ");
		String password = s.nextLine();
		System.out.println();
			
		if(!map.containsKey(id)) {
			System.out.println("입력하신 id는 존재하지 않습니다. 다시 입력해주세요.");
			continue;
		}
			
		if(!(map.get(id)).equals(password)) {
			System.out.println("비밀번호가 일치하지 않습니다. 다시 입력해주세요");
		}
		else {
			System.out.println("id와 비밀번호가 일치합니다.");
			break;
		}
	}
}

출력결과 :

id와 password입력  
id 입력 : asdf
password : 1111

비밀번호가 일치하지 않습니다. 다시 입력해주세요
id와 password입력  
id 입력 : asdf
password : 1234

id와 비밀번호가 일치합니다.

asdf 키에 처음에는 1111 로 비밀번호를 설정하였고

두번째는 1234로 설정하였다.

이 때, 1234가 비밀번호인 걸 확인할 수 있고

이것은 put을 했을 때 같은 키가 있다면 값을 덮어씌운다는 것을 알 수 있다.

3개의 데이터 쌍을 저장했지만, 실제로는 2개의 데이터 쌍만 저장된 것이다.

  • HashTable은 key나 value로 null을 허용하지 않지만,

    HashMap은 허용한다.

    그래서 'map.put(null, null);' 이나 'map.get(null);'이 가능하다


기본메서드 이용하여 데이터 저장 후 읽는 예제

public static void main(String[] args) {
	HashMap map = new HashMap();
	map.put("김자바", new Integer(100));
	map.put("이자바", new Integer(100));
	map.put("강자바", new Integer(80));
	map.put("안자바", new Integer(90));
	
	Set set = map.entrySet();
	Iterator it = set.iterator();
	
	while(it.hasNext()){
		Map.Entry e = (Map.Entry)it.next();
		System.out.println("이름 : "+e.getKey()+e.getValue());
	}
	set = map.keySet();
	System.out.println("참가자 명단 : "+set);
	
	Collection values = map.values();
	it = values.iterator();
	
	int total = 0;
	
	while(it.hasNext()) {
		Integer i = (Integer)it.next();
		total += i.intValue();
	}
	
	System.out.println("총점 : "+total);
	System.out.println("평균 : "+(float)total/set.size());
	System.out.println("최고점수 : "+Collections.max(values));
	System.out.println("최저점수 : "+Collections.min(values));
}

출력 결과 :

이름 : 안자바90
이름 : 김자바100
이름 : 강자바80
이름 : 이자바100
참가자 명단 : [안자바, 김자바, 강자바, 이자바]
총점 : 370
평균 : 92.5
최고점수 : 100
최저점수 : 80
  • entrySet()을 이용하여 키와 값을 함께 읽기

  • keySet()이나 value()를 이용해서 따로 읽기

두가지 기본 메서드의 기능을 확인할 수 있다.


하나의 키에 복수의 데이터 저장하는 예제

static HashMap phoneBook = new HashMap();
	
public static void main(String[] args) {
	addPhoneNo("친구", "이자바", "010-111-1111");
	addPhoneNo("친구", "김자바", "010-222-2222");
	addPhoneNo("친구", "김자바", "010-333-3333");
	addPhoneNo("회사", "김대리", "010-444-4444");
	addPhoneNo("회사", "김대리", "010-555-5555");
	addPhoneNo("회사", "박대리", "010-666-6666");
	addPhoneNo("회사", "이과장", "010-777-7777");
	addPhoneNo("세탁", "010-888,8888");
	
	printList();
}

// 그룹에 전화번호 추가
static void addPhoneNo(String groupName, String name, String tel) {
	addGroup(groupName);
	HashMap group = (HashMap)phoneBook.get(groupName);
	group.put(tel, name);	// 이름은 중복될 수 있으니 전화번호 key로!
}

// 그룹을 추가
static void addGroup(String groupName) {
	if(!phoneBook.containsKey(groupName)) {
		phoneBook.put(groupName, new HashMap());
	}
}

static void addPhoneNo(String name, String tel) {
	addPhoneNo("기타", name, tel);
}
	
// 전화번호부 전체 출력
static void printList() {
	Set set = phoneBook.entrySet();
	Iterator it = set.iterator();
	
	while(it.hasNext()) {
		Map.Entry e = (Map.Entry)it.next();
		
		Set subSet = ((HashMap)e.getValue()).entrySet();
		
		Iterator subIt = subSet.iterator();
		
		System.out.println(" * "+e.getKey()+"["+subSet.size()+"]");
		
		while(subIt.hasNext()) {
			Map.Entry subE = (Map.Entry)subIt.next();
			String telNo = (String)subE.getKey();
			String name = (String)subE.getValue();
			System.out.println(name+" "+telNo);
		}
		System.out.println();
	}
}

출력 결과 :

 * 기타[1]
세탁 010-888,8888

 * 친구[3]
이자바 010-111-1111
김자바 010-222-2222
김자바 010-333-3333

 * 회사[4]
이과장 010-777-7777
김대리 010-444-4444
김대리 010-555-5555
박대리 010-666-6666

HashMap은 데이터와 키 값을 모두 Object로 저장하기 때문에!

HashMap의 값으로 HashMap을 다시 저장할 수 있다!


문자열을 HashMap에 저장하고 는 예제

public static void main(String[] args) {
	String[] data = {"A", "K", "A", "K", "D", "K", "A", "K", "K", "K", "Z", "D"};
	HashMap map = new HashMap();
	
	for(int i=0; i<data.length; i++) {
		if(map.containsKey(data[i])) {
			Integer value = (Integer)map.get(data[i]);
			map.put(data[i], new Integer(value.intValue() +1));
		}
		else {
			map.put(data[i], new Integer(1));
		}
	}
	Iterator it = map.entrySet().iterator();
	
	while(it.hasNext()) {
		Map.Entry entry = (Map.Entry)it.next();
		int value = ((Integer)entry.getValue()).intValue();
		System.out.println(entry.getKey()+" : "+ printBar('#', value) +" "+value);
	}
}//main

public static String printBar(char ch, int value) {
	char[] bar = new char[value];
	for(int i=0; i<bar.length; i++) {
		bar[i] = ch;
	}
	return new String(bar);	// String(char[] chArr)
}

출력 결과 :

A : ### 3
D : ## 2
Z : # 1
K : ###### 6

문자열을 하나씩 읽어서 HashMap에 키로 저장하고 값을 1로 저장

HashMap에 같은 문자열이 키로 저장되어 있는지 확인하고 같은 문자열이면 1을 증가시킨다.

한정된 범위 내에 있는 순차적인 값들의 빈도수는 배열을 이용하지만,

이처럼 한정되지 않은 범위비순차적인 값들의 빈도수는 HashMap을 이용하여 구할 수 있다.

profile
keep going on~

0개의 댓글