ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 컬렉션 Map - HashMap
    백엔드/자바 2020. 8. 17. 00:58

    HashMap이란?

    Map 인터페이스를 구현한 클래스로 Map의 특징을 그대로 갖는다.

     

    Map은 키(key)와 값(value) 한쌍으로 구성된 자료구조를 말한다.

     

    HashMap은 해싱 기법을 사용해 Map의 형태로 자료를 저장하게 된다.

     

    이때 Map의 형태로 저장할 때 key객체와 value객체를 멤버로 가진 Entry 객체를 이용한다.

     

    간단히 저장되는 방식을 그림을 보자면 아래와 같다.

     

     

     

    데이터를 Map의 형태로 저장하면 위 그림처럼 키, 값으로 나눠진다.

     

    (HashMap 뿐 아니라 TreeMap도 위와 같은 방식으로 객체에 데이터를 저장한다.)

     

    이때 알아둬야 할 것은 값(value)는 중복되어도 상관없지만, 키(key)는 중복되선 안된다.

     

    만약 키가 중복될 경우에는 기존에 있던 키의 값은 새로 입력한 키의 값으로 갱신이 되기 때문이다.

     

    만약 Map을 사용하면서 순서까지 지키고 싶다면 LinkedHashMap을 이용하면 된다.

    HashMap의 내부 구조

     

    지금은 다소 바뀌었지만, 과거 HashMap 내부에는 그림처럼 Entry 자료형을 저장하는 배열이 있었다.

     

    (코드는 바뀌었으나, 기본적인 동작원리는 같아서 이해하기 쉽게 과거 코드를 참고한다.)

     

    만약 우리가 자료를 입력할 때 키와 값를 입력하면 이 데이터들은

     

    key객체와 value 객체를 하나로 묶은 Entry라는 객체에 저장된다.

     

    그리고 HashMap은 이러한 Entry 자료형을 저장할 수 있는 배열에 이 객체를 저장하는 것이다.

     

    앞서 말했듯 지금은 구조가 바뀌었지만, 기본적인 동작 원리는 이런식으로 돌아간다.

     

    또한 여전히 HashMap을 다룰 때 Entry에 저장되는 것은 변함없기 때문에 저장이 어떤 식으로

     

    이뤄지는지 안다면 HashMap을 이해하기 더 쉽다.

    해싱(Hashing)에 대해서

    앞서 HashMap은 해싱 기법을 사용해 Map 형태로 데이터를 저장한다고 말했다.

     

    여기서 해싱이란 무엇일까?

     

    간단히 말하면 주어진 데이터를 함수를 사용해 결과물을 반환받는다.

     

    그리고 해당 결과물을 이용해서 데이터를 저장하고 읽는 것을 말한다.

     

    예를 들어 이야기해보자.

     

     

     

    병원에서 위와 같이 고객 이름, 주민 번호가 적힌 서류를 갖고 있고,

     

    이것을 서류함에 정리해야한다고 가정해보자.

     

    담당자는 이 서류들을 출생연도에 맞게 분류하고 싶었다.

     

     

     

    하지만 1년 단위로 하기에는 서류함이 부족해 위 그림과 같이 연대순으로 서류함을 만들었다.

     

     

     

    그리고나서 고객 서류들을 필터링을 거쳐서 서류함에 정리를 해두었다.

     

     

     

    그리고 며칠 뒤 누군가 89년생 윤재준 고객의 정보를 요청했다.

     

    이에 담당자는 80년대 서류함을 뒤져서 윤재준의 데이터를 찾아 전달했다.

     

    이 과정이 해싱이다.

     

     

    우선 저장 과정부터 정리해보자.

     

     

    - 데이터의 키(key)를 해시함수에 전달.

     

    - 해시 함수(Hash Funtion)는 내부적으로 계산해서 해시코드를 반환하고 이것을 인덱스로서 이용함.

    예를 들어 95xxxx => 90, 89xxxx => 80 이런식으로 해시함수를 거치면 해시코드가 나옴.

    이 해시코드를 인덱스로서 사용함.

     

    - 해당 인덱스를 기준으로 만들어진 테이블에 Entry 객체 (Entry<key, value>)형태로 데이터를 저장한다.

     

     

     

    이때 데이터가 저장되는 테이블을 해시테이블(Hash Table)이라 한다.

     

    해시 테이블이란 배열과 연결리스트(LinkedList)가 결합된 형태의 테이블

     

    인덱스를 기준으로 Entry 타입의 데이터들을 연결리스트 형식으로 저장한다.

     

    해시테이블은 배열+연결리스트가 결합된 상태라서

     

    배열의 장점인 빠른 조회가 가능하고, 연결리스트의 장점인 자료의 빠른 추가 삭제도 가능하다.

     

     

    이제 읽기 과정을 정리해보자. 참고로 읽기도 저장과 별다를 바가 없다.

     

     

    - 데이터의 키(key)를 해시함수에 전달.

     

    - 해시 함수(Hash Funtion)는 내부적으로 계산해서 해시코드를 반환함.

     

    - 해시코드와 동일한 인덱스 탐색

     

    - 해당 인덱스에 저장된 LinkedList에서 키(key)가 동일한 Entry객체를 탐색하고 반환함.

     

    과정을 쭉 보면 알겠지만 해싱에서 해시 함수는 읽기 쓰기 모두에 쓰이는 중요한 요소다.

     

    이 내용을 바탕으로 알 수 있는 해시 함수의 중요한 법칙이 하나 있다.

     

    그건 바로 해시 함수는 언제든지 같은 값을 입력하면 같은 결과물을 반환해야한다는 것이다.

     

    위의 예시를 보면 89xxxxx를 입력해서 80이 나와서 80년대생 서류함에 서류를 저장했다.

     

    그런데 반대로 서류를 찾을 때 89xxxxxx를 입력했는데 70이 나온다면 서류를 찾을 수 없을 것이다.

     

    그래서 해시 함수는 항상 같은 값을 입력하면 같은 결과물을 반환해야한다.

    HashMap 이용해보기

     

    HashMap을 이용하기 위해선 선언을 해야하는데 HashMap은 Map인터페이스를 구현한 것이므로

     

    자료형을 Map으로 하더라도 사용이 가능하다.

     

     

     

     

    HashMap에 데이터를 넣을 때는 위 코드처럼 put() 메서드를 이용한다.

     

    그리고 put에는 매개변수로 키, 값을 입력해줘야 한다.

     

    이때 주의할 점은 키는 중복되지 않아야 한다는 것이다.

     

    put()메서드를 사용하고 HashMap을 출력해보면 위와 같은 결과물을 확인할 수 있다.

     

     

     

     

    HashMap에 들어간 데이터를 삭제할 때는 remove()메서드를 사용하면 된다.

     

    이때는 키(key)만 있으면 된다.

     

    왜냐하면 위에서 계속 이야기했지만 키는 중복되지 않는 유일값이기 때문이다.

     

    결과를 보면 위와 같이 "no5" 키를 가진 객체가 삭제된 것을 확인할 수 있다.

     

     

     

     

    내용을 수정하고 싶다면 replace()메서드를 사용하면 된다.

     

    현재 저장되있는 key값 중 바꾸고 싶은 key값을 입력한다.

     

    그리고나서 바꾸고 싶은 내용을 입력하면 변경이 된다.

     

     

     

    전체 Map 데이터 중 단 한개만 얻고 싶다면 위와 같이 get()메서드를 써준다.

     

    이때 get()은 Object를 반환하기 때문에 필요할 경우 형변환이 필요하다.

     

     

     

     

    값을 한꺼번에 확인하고 싶다면 위와 같이 메서드를 써주면 된다.

     

    entrySet()은 Map 전체의 데이터를 전달 받는 메서드다.

     

    keySet()은 Map에서 key의 데이터값만 전달받는 메서드다.

     

    values()는 Map에서 value의 데이터값만 전달받는 메서드다.

     

    이때 values()는 반환값이 Collection이라 위의 예시처럼 한번에 출력하고 싶다면 List로 바꿔야한다.

     

     

     

     

    Map안에 키나 값이 있는지 확인하고 싶다면 containsKey(), containsValue()를 사용하면 된다.

     

    반환 타입은 boolean이다.

    '백엔드 > 자바' 카테고리의 다른 글

    컬렉션 - MAP 출력 방법  (0) 2020.08.17
    컬렉션 Map - TreeMap  (0) 2020.08.17
    컬렉션 Set - TreeSet  (0) 2020.08.16
    컬렉션 Set - HashSet  (0) 2020.08.16
    컬렉션 List - Stack & Queue  (0) 2020.08.16
Designed by Tistory.