✔ 참고출처 : https://surhommejk.tistory.com/223 ✔ 참고출처 : https://brocess.tistory.com/210 ✔ 개인적으로 공부하면서 정리해나가고 있습니다. 맞지 않은 내용이 있을 수 있습니다. ✔ 맞지 않는 내용을 계속 고쳐나갈 수 있도록 하겠습니다. |
코딩 문제 풀이를 하다보면 Map, HashMap을 많이 사용하게 되는데
이상한 현상을 목격했다.
1) Map에 put 하는 순서와 다르게 출력된다
2) key값에 Interger 형이 오면 숫자의 순서대로 출력된다
Map<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("사과", 10);
map1.put("딸기", 20);
map1.put("포도", 30);
System.out.println("map1 = " + map1);
Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
map2.put(3, 10);
map2.put(1, 20);
map2.put(2, 30);
System.out.println("map2 = " + map2);
HashMap 2가지를 만들고 입력한 순서대로 출력되는지 확인해 보았다
결과는 다음과 같다
map1 = {포도=30, 사과=10, 딸기=20}
map2 = {1=20, 2=30, 3=10}
Map에는 순서가 없어서 입력(put)한 순서대로 출력된다고 생각했었는데 기대와 달랐다.
어떤 기준이 있는 것일까?
Map put 메소드를 보면 해시값을 가지고 입력값을 저장하는 것을 알 수 있다.
//interface Map #put
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
위에서 작성했던 map1의 해시코드를 출력해보면 다음과 같다.
Map<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("사과", 10);
map1.put("딸기", 20);
map1.put("포도", 30);
System.out.println("hashCode = " + map1.hashCode());
//hashCode = 4783884
여기서 또 궁금한 점은
각각의 key의 출력되는 순서가 hashcode와 무슨 연관이 있는지이다.
각 key마다 hashcode 값이 있어서 그 순서대로 출력되는건지 궁금하다
아래 api에서 Map의 해시코드는 entryset의 각 entry들의 해시코드 합으로 정의된다고 나와있다.
즉, 이말은 각 entry가 해시코드 값을 가지고 있다는 의미 아닐까?
int hashCode()
Returns the hash code value for this map. The hash code of a map is defined
to be the sum of the hash codes of each entry in the map's entrySet() view.
This ensures that m1.equals(m2) implies that m1.hashCode()==m2.hashCode()
for any two maps m1 and m2, as required by the general contract of Object.hashCode().
[출처] https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Map.html#hashCode()
EntrySet에서 각 entry를 뽑아서 해시코드를 출력해 보았다.
Map<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("사과", 10);
System.out.println("key:사과 hashCode = " + map1.hashCode());
map1.put("딸기", 20);
System.out.println("key:딸기 hashCode = " + map1.hashCode());
map1.put("포도", 30);
System.out.println("key:포도 hashCode = " + map1.hashCode());
System.out.println("map1 = " + map1);
for (Map.Entry<String, Integer> entry : map1.entrySet()) {
System.out.println("entry.hashCode() = " + entry.hashCode());
}
결과는
hashCode = 1573338
hashCode = 3056070
hashCode = 4783884
map1 = {포도=30, 사과=10, 딸기=20}
포도 entry.hashCode() = 1727814
사과 entry.hashCode() = 1573338
딸기 entry.hashCode() = 1482732
각 entry에 저장된 해시코드 값이 출력되었다.
결국 map1을 println으로 출력할 때 뿐만아니라, 확장 for문으로 접근할 때에도 각 entry의 해시코드값에 접근하여 그 순서대로 출력하는 것을 알 수 있었다.
또, api 에 적혀있던 합계 entry의 해시코드값의 합계가 entrySet의 해시코드값과 같다는 것도 확인할 수 있었다.
1727814+1573338+1482732 = 4783884
그런데 여기서 또 이상한 점 발견
Map<String, Integer> 은 해시코드값이 큰 순서대로 접근을 했는데, Map<Integer, Integer> 에서는 key의 수가 작은 수부터 접근했다는 것이다.
그렇다면 Integer 타입의 해시코드값은 작은 수일수록 큰 것일까?
Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
map2.put(3, 10);
map2.put(1, 20);
map2.put(2, 30);
map2.put(-1, 40);
map2.put(0, 50);
System.out.println("map2 = " + map2);
for (Map.Entry<Integer, Integer> entry : map2.entrySet()) {
System.out.println(entry.getKey() + " entry.hashCode() = " + entry.hashCode());
결과는
map2 = {-1=40, 0=50, 1=20, 2=30, 3=10}
-1 entry.hashCode() = -41
0 entry.hashCode() = 50
1 entry.hashCode() = 21
2 entry.hashCode() = 28
3 entry.hashCode() = 9
Integer 형 Map의 출력순서는 해시코드값의 크기와는 상관이 없는 것 같다.
Integer 형 key의 그 숫자의 순서대로(오름차순) 출력 되는 것으로 보인다.
Map<integer, Integer> 형태 뿐만아니라 Map<Integer, String> 형태에도 key의 그 숫자 순서대로 출력된다.
이 부분은 api 나 다른 자료를 더 참고해보아야 할 것 같다.
결론
1. Map에 데이터를 저장(put)할 때 해시코드값을 같이 저장한다.
2. HashMap은 순서가 보장되지는 않지만 접근시(출력시) 저장된 해시코드값에 영향을 받는다.
3. HashMap의 key가 String형이면 각 entry의 해시코드값이 큰 순서대로 출력되고, key가 Integer 형이면 key의 수 크기 순서대로(오름차순) 출력된다.
4. 어떤 데이터를 key가 Integer인 Map에 모을 경우, 따로 정렬하지 않아도 key의 오름차순으로 출력된다(?)
추가
* 순서가 보장되는 LinkedHashMap과 어떻게 다를까?
댓글