[Java] HashMap (컬렉션)인터페이스를 알아보자!

2020-12-25


우선 Map이란 컬렉션은 key와 value를(key와 value는 모두 객체이다.) 구성된 entry 객체를 저장하는 자료구조이다. 예를 들자면 [ Map <String, Integer> map =... ]와 같은 코드가 작성되어 있다면 Map이라는 컬렉션에 키는 String이며, 값으로 Integer 타입의 객체가 들어가고 변수의 이름은 map이라고 해석할 수 있다.

 

그중에서 HashMap은 Map 컬렉션을 구현하는 대표적 인터페이스이다. 다만 HashMap은 hashcode와 equals 메서드를 재정의 하여 동등 객체의 처리 조건을 재정의 해야 한다. 그러면 사용법을 알아보자.


package mMap;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class main {
	public static void main(String[] args) {
		Map<String, Integer> map = new HashMap<>();
		
		map.put("a", 111);
		map.put("b", 222);
		map.put("c", 333);
		map.put("d", 444);
		map.put("f", 555);

        	}
}

선언 방법은 위와 같이 간단하다. Map 컬렉션에 키는 String  /  값은 Integer로 주었으며, new 연산자를 통해 HashMap객체를 만들어주면 된다. 이후 해당 객체에 데이터를 입력 시 put 메서드를 통해 키와 값을 입력해주면 된다.

 

다만 여기서 궁금증이 생길 수 있다. 위에서 HashMap은 hashcode와 equals 메서드를 재정의 해야 한다고 했는데, 위의 코드에서는 해당 부분을 확인할 수 없다. 그 이유는 이미 String은 해당 두 메서드가 재정의 되어 있기 때문이다. 그래서 HashMap을 사용할 때에는 키 값을 String으로 사용하는 경우가 많이 있다.


이제 넣어둔 데이터를 출력하는 코드를 알아보자.

package mMap;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class main {
	public static void main(String[] args) {
		Map<String, Integer> map = new HashMap<>();
		
		map.put("a", 111);
		map.put("b", 222);
		map.put("c", 333);
		map.put("d", 444);
		map.put("f", 555);
		
		Set<String> keySet = map.keySet();
		//전체 키를 Set으로 받아서 넣는다.
		Iterator<String> it = keySet.iterator();
		//반복해서 키를 꺼내기 위해 Iterator에 해당 키를 다시 담는다.
		while(it.hasNext()) {
			String key = it.next();
			//해당 키값을 변수에 담음
			Integer value = map.get(key);
			//키 값은 get에 넣어 해당 값을 찾음 
			System.out.println(key + " = " + value);
			//두가지 모두 출력
		}
		
		Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
		//set에 map.entry 객체를 모두 담음
		Iterator<Map.Entry<String, Integer>> entryIt= entrySet.iterator();
		//마찬가지로 반복해서 키를 꺼내기 위해 Iterator에 해당 키를 다시 담는다.
		while(entryIt.hasNext()) {
			 System.out.println(entryIt.next());
			 //반복자에 이미 키와 값이 모두 들어가 있어 next 메서드로 꺼내면된다.
		}
        	}
}

전체 데이터를 출력하는 방법은 위와 같이 기본 Set 컬렉션에 키의 타입을 넣어준 후 반복자로 꺼내 주는 방법과 처음부터 map.entry 객체를 Set에 담아 출력하는 방법이 있다. 둘 중 아무거나 사용해도 상관없다. 출력 값은 아래와 같다.


그러면 이제 클래스를 키값으로 받는 HashMap 은 어떻게 사용하는지 알아보자. 예제로 사용할 클래스 Human은 아래와 같은 코드를 정의되어 있다.

package mMap;

public class Human {
	
	private String name;
	private String age;
	
	public Human(String name, String age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAge() {
		return age;
	}
	public void setAge(String age) {
		this.age = age;
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Human) {
			Human human = (Human) obj;
			return human.name.equals(name) && human.age.equals(age);
		}else {
			return false;
		}
	}
	
	@Override
	public int hashCode() {
		return name.hashCode() + age.hashCode();
	}

}

해당 코드를 보면 앞서 말했듯이 hashcode와 equals 메서드가 재정의 된 것을 알 수 있다. equals의 경우 클래스 생성자로 들어온 값이 클래스의 인스턴스인지 확인한 후 맞다면 해당 클래스 타입으로 강제 변환한다. 이후 각 필드 값 역시 equals로 체크 후 true 값을 리턴한다.

 

hashcode는 클래스의 필드 값 두 개를 hashcode로 리턴하도록 재정의 하였다.

 

이제 메인 클래스의 실행 코드를 살펴보자.

package mMap;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class main {
	public static void main(String[] args) {
    		Map<Human, Integer> map = new HashMap<>();
		
		map.put(new Human("aaa", "25"), 1);
		map.put(new Human("bbb", "25"), 2);
		map.put(new Human("ccc", "30"), 3);
		map.put(new Human("ddd", "30"), 4);
		map.put(new Human("fff", "40"), 5);	
		
		Set<Human> key1 = map.keySet();		
		//전체 키를 Set으로 받아서 넣는다.
		Iterator<Human> it1 = key1.iterator();
		//반복해서 키를 꺼내기 위해 Iterator에 해당 키를 다시 담는다.
		while(it1.hasNext()) {
			Human h = it1.next();
			int v = map.get(h);		
			System.out.println(h.getAge()  + " " + h.getName() + " " + v);
			//이후 get메서드를 통해 필드값들을 출력한다.
		}
		
		System.out.println("______________________________________________________________________________");
		Set<Map.Entry<Human, Integer>> key = map.entrySet();
		//맵에 구성요소 전체로 셋의 매개값으로 받아 변수에 저장
		Iterator<Map.Entry<Human, Integer>> it = key.iterator();
		//반복해서 하나씩 꺼내기 위해서 Iterator 변수에 다시 담아줌
		while(it.hasNext()) {
			//값이 있나 우선적 확인
			Map.Entry<Human, Integer> entry = it.next();
			//맵 엔트리 변수에 순서대로 하나씩 담아 초기화
			Human h = entry.getKey();
			//키 클래스의 변수에 키값 저장
			System.out.println(h.getAge() + " " +h.getName() + " " + entry.getValue());
		}
        		
	}
}

실행코드는 기존에 String을 사용한 코드와 크게 다르지 않아 설명은 생략하도록 하겠다. 주석으로 자세한 설명을 적어 두었으니, 이클립스 또는 인텔리제이에 해당 코드르 복사 후 컴파일해보면 금방 이해가 될 것이다.