해시 맵의 작업 원칙은 최근 몇 년 동안 일반적인 Java 인터뷰 질문입니다. 거의 모든 Java 프로그래머는 해시 맵을 알고, 해시 맵을 사용할 위치를 알고 있으며, 해시 가능과 해시 맵의 차이점을 알고 있습니다. 그렇다면이 인터뷰 질문이 왜 그렇게 특별합니까? 이 질문은 매우 깊기 때문입니다. 이 질문은 종종 고급 또는 중간 수준의 인터뷰에서 나타납니다. 투자 은행은이 질문을 선호하며 프로그래밍 기술을 조사하기 위해 해시 맵을 구현하도록 요청할 수도 있습니다. ConcurrenthashMap 및 기타 동기 세트의 도입은이 문제를 더욱 복잡하게 만듭니다. 탐험의 여정을 시작합시다!
먼저 간단한 질문을하자
"해시 맵을 사용해 보셨습니까?" "해시 맵이란 무엇입니까? 왜 그것을 사용 했습니까?"
거의 모든 사람이 "예"에 대답 한 다음 해시 맵과 같은 해시 맵의 일부 기능에 답할 수 있습니다. 예를 들어 해시 테이블은 널 키 값과 값을 받아 들일 수 있습니다. 해시 맵은 비 동기화되어 있습니다. 해시 맵은 빠릅니다. 해시 맵은 키 가치 쌍 등을 저장합니다. 이것은 당신이 해시 맵을 사용했으며 그것에 친숙하다는 것을 보여줍니다. 그러나 면접관은 빠른 변화를 일으켜 Hashmap의보다 기본적인 세부 사항에 대해 지금부터 까다로운 질문을 시작했습니다. 면접관은 다음과 같은 질문을 할 수 있습니다.
"해시 맵이 어떻게 작동하는지 아십니까?" "Hashmap의 get () 메소드가 어떻게 작동하는지 아십니까?"
"표준 Java API를 자세히 찾지 못했고 Java 소스 코드 또는 Open JDK를 볼 수 있습니다." "Google에서 답을 찾을 수 있습니다."
그러나 일부 면접관은 "해시 맵은 해싱의 원리를 기반으로합니다. 우리는 풋 (키, 값)을 사용하여 객체를 해시 맵에 저장하고 get (key)를 사용하여 hashmap에서 객체를 얻습니다. 키와 값을 put () 방법에 전달할 때, 우리는 먼저 키와 hashcode () 메소드를 호출 할 때, 반환 된 Hashcode는 집단을 찾는 데 사용됩니다. 여기서 중요한 점은 해시 맵이 버킷의 핵심 개체와 가치 객체를 Map.entry로 저장한다는 것을 지적하는 것입니다. 이것은 객체를 얻는 논리를 이해하는 데 도움이됩니다. 이것을 깨닫지 못하거나 실수로 값을 버킷에 저장한다고 생각한다면 해시 맵에서 객체를 얻는 방법의 논리에 대한 답변에 답하지 않을 것입니다. 이 답변은 매우 정확하며 면접관이 해싱과 해시 맵의 작동 방식을 알고 있음을 보여줍니다. 그러나 이것은 이야기의 시작일뿐입니다. 면접관이 Java 프로그래머가 매일 만나야하는 실제 장면에 합류하면 잘못된 답변이 자주 나타납니다. 다음 질문은 해시 맵의 충돌 감지 및 충돌 솔루션에 관한 것일 수 있습니다.
"두 객체의 해시 코드가 동일하면 어떻게됩니까?" 여기에서 실제 혼란이 시작되고 일부 면접관은 해시 코드가 동일하기 때문에 두 객체는 동일하며 해시 맵은 예외를 제외하거나 저장되지 않습니다. 그런 다음 면접관은 두 가지 방법이 있음을 상기시킬 수 있습니다. 일부 면접관은 포기할 수 있지만 다른 면접관은 계속 발전 할 수 있습니다. "해시 코드는 동일하기 때문에 버킷 위치는 동일하며 '충돌'이 발생합니다. Hashmap은 링크 된 목록을 사용하여 객체를 저장하기 때문에이 항목 (맵. 키 값 쌍이 포함 된 객체 객체)은 링크 된 목록에 저장됩니다." 이 답변은 매우 합리적입니다. 충돌을 다루는 방법에는 여러 가지가 있지만이 방법이 가장 쉽고 해시 맵의 처리 방법입니다. 그러나이 이야기는 아직 끝나지 않았으며 면접관은 계속 묻습니다.
"두 키의 해시 코드가 동일하다면 값 객체를 어떻게 얻습니까?" 면접관이 대답합니다. get () 메소드를 호출하면 Hashmap은 키 객체의 해시 코드를 사용하여 버킷 위치를 찾은 다음 값 객체를 얻습니다. 면접관은 두 값 객체가 동일한 버킷에 저장되면 대답을합니다. 링크 된 목록은 값 객체가 발견 될 때까지 통과합니다. 면접관은 비교할 값 객체가 없기 때문에 값 객체를 찾을지 여부를 어떻게 결정 했습니까? 면접관이 해시 맵이 링크 된 목록에 저장할 때까지 링크 된 목록에 키 가치 쌍을 저장하지 않으면이 질문에 답할 수 없습니다.
이 중요한 지식 지점을 기억하는 일부 면접관은 버킷 위치를 찾은 후 keys.equals () 메서드를 호출하여 링크 된 목록에서 올바른 노드를 찾아서 마지막으로 찾을 수있는 값 개체를 찾을 것이라고 말할 것입니다. 완벽한 답변!
대부분의 경우 면접관은 hashcode () 및 equals () 메소드를 혼동하기 때문에이 링크에서 실수를 저지 릅니다. 이 hashcode ()가 반복적으로 나타나기 전에 값 () 메소드는 값 객체를 얻을 때만 나타납니다. 일부 우수한 개발자들은 불변의 선언 된 객체를 최종적으로 사용하고 적절한 equals () 및 hashcode () 메소드를 사용하면 충돌 발생이 줄어들고 효율성을 향상시킬 것이라고 지적 할 것입니다. 불변성으로 인해 다른 키의 해시 코드가 캐시 될 수 있으므로 전체 물체를 얻는 속도가 높아집니다. String 및 Interger와 같은 래퍼 클래스를 키로 사용하는 것이 매우 좋습니다.
여기에 있다고 생각되면 다음 질문을들을 때 놀랄 것입니다. "해시 맵의 크기가 하중 계수에 의해 정의 된 용량을 초과하면 어떨까요?" Hashmap의 작동 방식을 실제로 알지 못하면이 질문에 대답하지 않을 것입니다. 기본 부하 계수 크기는 0.75입니다. 즉, 맵이 다른 컬렉션 클래스 (예 : Arraylist 등)와 같이 75% 버킷을 채우면 원래 해시 맵의 두 배 크기 인 버킷 배열이 맵을 조정하고 원래 객체를 새 버킷 어레이에 넣을 수 있도록 만들어집니다. 이 프로세스는 해시 방법을 호출하여 새 버킷 위치를 찾기 때문에 재사용이라고합니다.
이 질문에 대답 할 수 있다면 다음 질문이옵니다. "해시 맵의 크기를 조정하는 데 어떤 문제가 있는지 이해합니까?" 대답하지 못할 수도 있습니다. 현재 면접관은 멀티 스레딩시 경주 조건이있을 수 있음을 상기시킬 것입니다.
해시 맵 크기를 조정할 때는 실제로 조건부 경쟁이 있습니다. 두 스레드 모두 해시 맵이 크기를 조정해야한다는 것을 발견하면 동시에 크기를 조정하려고합니다. 크기 조정 프로세스 중에 링크 된 목록에 저장된 요소의 순서가 반전됩니다. 새 버킷 위치로 이동할 때 Hashmap은 링크 된 목록의 끝에 요소를 배치하지 않고 머리에 꼬리가 횡단을 피하기 때문에 요소를 배치하기 때문입니다. 조건부 경쟁이 발생하면 악순환이 있습니다. 현재 면접관에게 왜 그렇게 이상한 지에 대해 다중 스레드 환경에서 해시 맵을 사용해야합니까? :)
열정적 인 독자들은 해시 맵에 대한 더 많은 질문을 제공합니다.
1. String 및 Interger와 같은 래퍼 클래스가 키로 적합한 이유는 무엇입니까? String 및 Interger와 같은 래퍼 클래스는 해시 맵 키로 가장 적합하며 String이 가장 일반적으로 사용됩니다. 문자열은 불변적이고 최종적이기 때문에 equals () 및 hashcode () 메소드가 다시 작성되었습니다. 다른 래퍼 클래스에는이 기능도 있습니다. hashcode ()를 계산하기 위해서는 키 값이 변경되는 것을 방지해야하기 때문에 불변성이 필요합니다. 키 값이 들어가거나 얻을 때 다른 해시 코드를 반환하면 해시 맵에서 원하는 객체를 찾을 수 없습니다. 불변성에는 실 안전과 같은 다른 장점이 있습니다. 필드를 최종으로 선언하여 해시 코드가 변경되지 않음을 보장 할 수 있다면 그렇게하십시오. 객체를 얻을 때 equals () 및 hashcode () 메소드가 사용 되므로이 두 메소드를 올바르게 다시 작성하는 것이 매우 중요합니다. 두 개의 불평등 한 객체가 다른 해시 코드를 반환하면 충돌 가능성이 작아서 해시 맵의 성능을 향상시킬 수 있습니다.
2. 사용자 정의 객체를 키로 사용할 수 있습니까? 이것은 이전 질문의 확장입니다. 물론 equals () 및 hashcode () 메소드의 정의 규칙을 따르는 한 객체를 키로 사용할 수 있으며 객체가 맵에 삽입 된 후에는 다시 변경되지 않습니다. 이 사용자 정의 객체가 불변이라면 이미 조건을 생성 한 후에 변경할 수 없기 때문에 조건을 키로 만족시킵니다.
3. cocurrenthashmap을 사용하여 해시 테이블을 대체 할 수 있습니까? 점점 더 많은 사람들이 동의어를 사용하기 때문에 이것은 매우 인기있는 인터뷰 질문입니다. Hashtable은 동기화되어 있음을 알고 있지만 ConsurenTashMap 동기화는 동기화 레벨에 따라 맵의 일부를 잠그기 때문에 더 좋습니다. ConsurenThashMap은 확실히 해시 테이블을 대체 할 수 있지만 Hashtable은 더 강한 스레드 안전성을 제공합니다. Hashtable과 ConcurrenThashmap의 차이점을 보려면이 블로그를 확인하십시오.
나는이 질문의 깊이와 폭에 다른 개념을 직접 포함하지 않기 때문에 개인적 으로이 질문을 매우 좋아합니다. 이러한 질문을 설계하는 데 어떤 지식이 있는지 살펴 보겠습니다.
요약
해시 맵의 작동 방식
Hashmap은 Hashing 원칙을 기반으로하며 put () 및 get () 메소드를 통해 객체를 저장하고 얻습니다. 키 값 쌍을 put () 메소드로 전달하면 키 객체의 hashcode () 메소드를 호출하여 해시 코드를 계산 한 다음 값 객체를 저장할 버킷 위치를 찾습니다. 객체를 얻을 때, 올바른 키 값 쌍이 키 객체의 equals () 메소드를 통해 찾은 다음 값 객체가 반환됩니다. Hashmap은 연결된 목록을 사용하여 충돌 문제를 해결합니다. 충돌이 발생하면 링크가 링크 된 목록의 다음 노드에 저장됩니다. 해시 맵은 각 링크 된 목록 노드에 키 값 쌍 객체를 저장합니다.
두 개의 다른 키 객체의 해시 코드가 동일하면 어떻게됩니까? 동일한 버킷 위치에 링크 된 목록에 저장됩니다. 키 객체의 equals () 메소드는 키 값 쌍을 찾는 데 사용됩니다.
Hashmap에는 많은 이점이 있기 때문에 Hashmap을 전자 상거래 응용 프로그램에서 캐시로 사용했습니다. Java는 금융 분야에서 많이 사용되기 때문에 성과를 고려하기 위해 종종 Hashmap 및 ConsherthashMap을 사용합니다. 해시 맵에 대한 더 많은 기사를 볼 수 있습니다.
해시 맵과 해시 가능의 차이
해시 맵과 해시 세트의 차이
원본 링크 : Javarevisited Translation : importnew.com -Tang Xiaojuan 번역 링크 : http://www.importnew.com/7099.html