[Java] HashMap

Jung In Lee·2024년 12월 26일
0

JAVA

목록 보기
9/9

해시맵의 키가 객체일때

  • 문제를 풀던 도중 객체에 equals, hashcode를 왜 오버라이드하는지 알수있게하는 문제를 발견했다.
import java.io.*;
import java.util.*;

public class Template {
    static class Point{
        int x;
        int y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

		@Override
        public boolean equals(Object obj){
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            Point point = (Point)obj;
            return x == point.x && y == point.y;
        }

        @Override
        public int hashCode(){
            return Objects.hash(x,y);
        }
    }



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

        Point point1 = new Point (3,4);
        Point point2 = new Point (3,4);
        Point point3 = null;
        Point point4 = null;

        pointMap.put(point1, pointMap.getOrDefault(point1, 0) + 1);
        pointMap.put(point2, pointMap.getOrDefault(point2, 0) + 1);
        pointMap.put(point3, pointMap.getOrDefault(point3, 0) + 1);
        pointMap.put(point4, pointMap.getOrDefault(point3, 0) + 1);

        // equals, hash 오버라이드 하지않을경우
        // 예상 출력 : 1 1 1 1
        // 실제 : 1 1 2 2
        // 같은 좌표만 묶지 못함.
        System.out.println(pointMap.get(point1));
        System.out.println(pointMap.get(point2));
        System.out.println(pointMap.get(point3));
        System.out.println(pointMap.get(point4));

        // equals, hash 오버라이드 했을경우
        // 예상 출력 : 2 2 2 2
        // 실제 출력 : 2 2 2 2
    }
}
  • 해시맵의 put 작동방식은 다음과같다.
  1. 먼저 같은값이 있는지 체크
  2. 있으면 그곳에 값을 대입
  • 위에서는 Map<Point, Integer>으로 객체의 카운팅을 하는 맵이다.

  • 요구사항은 같은 좌표를 동등시하여 카운트를 올리는 방식이다.

  • 해시맵에서는 그대로 사용하면 위의 (3,4) 좌표는 서로 다르게 계산된다.

  • 좀더 구체적으로 해시맵의 put방식을 살펴보면,

  • hashmap은 키의 동등성을 비교할때 hashcode를 먼저 사용하고, equals를 통해 추가적으로 확인한다.

  1. hashcode()를 사용해서 저장할 버킷을 결정하고
  2. 같은 공간안에 동일한 key가있는지 equals로 비교한다.
  • 즉, equals를 오버라이딩하지않으면 객체 메모리 주소 기반으로 hashcode를 반환하고, equals는 주소값을 동등비교밖에 하지않는다.

  • 상위 메소드를 타고 올라가면

  • 주소 동등비교 밖에 없다.

  • 값을 비교하려면 따로 커스텀해서 지정해줘야한다.

  • 따라서 원하는 연산인 두 좌표가 같음에도 불구하고 같은 좌표로 카운트되지않는다.

  • 문제로 돌아가서 커스텀하고 싶은것은 hashcode 함수도 포함이다.

        @Override
        public int hashCode(){
            return Objects.hash(x,y);
        }
  • 해당 메소드는 x,y 좌표를 매개변수로 Objects의 클래스의 도움을 받아 해시코드를 생성한다.
  • 그리고 equals에 오버라이딩한 설명은 다음과같다.
        @Override
        public boolean equals(Object obj){
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            Point point = (Point)obj;
            return x == point.x && y == point.y;
        }
profile
Spring Backend Developer

0개의 댓글