JAVA 용기 에 대한 HashMap
6808 단어 HashMap
다음은 재 미 있 는 부분 을 말씀 드 리 겠 습 니 다.
1. key = null 에 대하 여.null 을 key 로 하면 액세스 속도 가 가장 빠르다 고 생각 합 니 다!put 와 get 전에 key 가 null 인지 아 닌 지 를 판단 하기 때문에 null 이면 key 가 null 인 값 을 직접 가 져 옵 니 다. 또한 key = null 이면 용기 Entry 배열 에 저 장 된 0 아래 표 시 를 직접 꺼 낼 수 있 습 니 다. 대상 이 Entry 배열 에 저 장 된 아래 표 시 는 하나의 hash 값 과 숫자의 길이 에 따라 줄 여 얻 은 것 입 니 다. key 가 null 이 라면 배열 아래 표 시 는 0 일 것 입 니 다.제때에 HashMap 자신 이 길이 조정 을 하고 다시 저장 할 때 도 마찬가지 입 니 다!빨리 기억 하 는 이 유 는 아래 가 0 이 라 서가 아니 라 put 와 get 전에 판단 하기 때 문 입 니 다!그러나 극단 적 인 상황 은 Entry [0] 라 는 체인 이 매우 길 고 속도 도 그리 빠 르 지 않다 는 것 이다.
2. HashMap 용량 변화.HashMap 용량 이 '부족' 할 때 용량 이 자동 으로 증가 합 니 다. 용량 을 늘 리 는 방식 은 지난번 배열 의 길이 * 2 입 니 다. HashMap 용량 을 수 동 으로 설정 하지 않 으 면 초기 값 은 16 이 고 loadfactor (기본 초기 값 은 0.75f) 가 현재 용량 증 가 를 진행 하 는 지 여 부 를 결정 합 니 다. 16 을 다 써 서 증가 하 는 것 이 아니 라 용량 > = loadfactor * 16 일 때 증가 합 니 다.이 인자 가 왜 0.75f 인지 에 대해 서 는 실천 에서 나 온 결론 일 수 있 습 니 다. 모든 기본 HashMap 은 12 개의 대상 을 넣 은 후에 다음 에 대상 을 놓 으 면 용량 크기 를 32 로 다시 바 꾸 고 다음 에 확장 여 부 를 판단 할 때 32 * loadfactor 로 결정 합 니 다.
3. put 일반 key, 일반 대상 의 과정.키 를 저장 합 니 다! =null 의 경우 대상 의 저장 과정 은 어 떻 습 니까?우 리 는 자주 String 을 key 로 사용 합 니 다. 식별 하기 편리 하기 위해 서 입 니 다. 사실은 key 도 일반적인 Object 대상 이거 나 자신 이 초기 화 한 대상 일 수도 있 습 니 다. 심지어 * class 일 수도 있 습 니 다. jvm 에서 볼 때 이것 은 여전히 Object 일 뿐 입 니 다. Object 라면 hashcode 가 있 습 니 다. 만약 에 hashcode 방법 을 복사 하지 않 았 다 면,자신 이 실현 한 대상 hashcode 는 jvm 대상 이 메모리 에 있 는 색인 값 을 직접 되 돌려 줍 니 다. 이것 이 바로 hashcode 자체 에 존재 하 는 의미 - 대상 의 빠 른 주소 지정 입 니 다.
됐어, 멀 지 않 아!계속 put 하 는 과정,
먼저 HashMap 에 저 장 된 원자 Entry 를 소개 합 니 다. 그 는 Map 인터페이스 안의 내부 인터페이스 입 니 다. HashMap 은 이 를 실 현 했 고 네 가지 속성 이 있 습 니 다. Key, value, next, hash 입 니 다.key 는 우리 가 사용 하 는 키 입 니 다. value 는 저 장 된 대상 입 니 다.next 는 사실 Entry 대상 이기 도 합 니 다. 이것 은 체인 구조 라 고 생각 할 수 있 습 니 다. 그 는 다음 Entry 대상 을 가리 키 고 Entry 의 구체 적 인 대상 에 긴 체인 구 조 를 저장 할 수 있 습 니 다. 마지막 끝의 대상 인 next 는 null 입 니 다.hash 라 는 것 은 Entry 배열 의 아래 표 시 를 계산 하 는 근거 로 잠시 생각 합 니 다.너 도 간단 한 색인 이 라 고 생각 할 수 있다.
HashMap 은 put 대상 전에 hash 를 먼저 얻 습 니 다. 이 hash 는 나중에 Entry 배열 의 아래 표 시 를 하 는 근거 중 하나 입 니 다. 사실은 다른 근 거 는 배열 의 길이 입 니 다!나중에 얘 기해.
hash 를 얻 는 과정 은 매우 복잡 합 니 다. 코드 를 보 세 요.
int hash = hash(key.hashCode());
...
//
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
먼저 key 의 hashcode 에 간 다음 에 징 그 러 운 부호 없 는 자리 이동 과 연산 을 했 습 니 다. 왜 자 리 를 옮 기 는 것 이 20, 12, 7, 4 인지 에 대해 의문 입 니 다. 마치 String 의 hashcode 가 왜 31 (제 블 로그 에서 토론 이 있 습 니 다) 인지........................................................
자, 여기 hash 라 는 값 을 계산 해 냈 습 니 다!HashMap 에 대상 을 저장 하기 전에 밑 에 배열 이 있 기 때문에 그 는 먼저 어떤 배열 아래 에 존재 해 야 하 는 지 계산 해 야 합 니까?그래서 다음 과 같은 계산 이 생 겼 다.
int i = indexFor(hash, table.length);
...//
//
static int indexFor(int h, int length) {
return h & (length-1);
}
왜 length - 1 이 냐 는 질문 이 있 을 수 있 습 니 다. 사실은 간단 합 니 다. 배열 이 경 계 를 넘 지 않 기 위해 서 는 결과 가 커지 면 length - 1 밖 에 안 됩 니 다.
자, 저장 할 배열 아래 표시 도 계산 되 었 습 니 다. 이제 대상 에 넣 어야 합 니 다.....................................................
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
// e.hash==hash ?
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
//
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
코드 를 보면 대상 을 넣 은 후에 바로 위 치 를 정 하 는 table [i] 를 볼 수 있 습 니 다. 안에 있 는 i 는 바로 이전 index For 에서 나 온 값 입 니 다.이 Entry 체인 으로 직접 와 서 나무 와 같은 key 를 비교 합 니 다. 주석 에 'e. hash = = hash' 라 고 쓰 여 있 는 것 은 검색 속 도 를 높이 기 위해 서 입 니 다.(우 리 는 항상 hashcode 와 equals 방법 을 덮어 씁 니 다. hashcode 가 같 지 않 으 면 바로 같은 대상 이 아니 라 고 판결 할 수 있 습 니 다. hashcode 가 같 으 면 equals 대 비 를 합 니 다. 일반적인 Object 를 덮어 쓰 는 equals 방법 이 없 는 대상 은 메모리 주소 가 같 는 지 비교 하 는 것 입 니 다)"직접 숫자의 대 비 는 key 의 대비 보다 빠 릅 니 다. hash 값 이 같 지 않 은 것 을 발견 하면 바로 다음 순환 대 비 를 실행 할 수 있 습 니 다. 찾 으 면 새로운 오래된 값 으로 교체 합 니 다. 찾 지 못 하면 바로 Entry 대상 을 이 Entry 체인 에 추가 하고 다음 절 을 주의 하 십시오.
// i
// int hash = hash(key.hashCode());
//int i = indexFor(hash, table.length);
addEntry(hash, key, value, i);
.....
//
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);//
}
이렇게 한 대상 이 들 어 갑 니 다!
넷 째, get 방법 에 대하 여.
public V get(Object key) {
if (key == null)
return getForNullKey();//key null
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
위의 코드 를 보면 한 가지 문 제 를 알 수 있 습 니 다.
hash 라 는 값 이 그렇게 중요 합 니 다. HashMap 을 도와 구체 적 으로 어떤 Entry 원 자 를 신속하게 찾 을 수 있 습 니 다. 현재 많은 회사 들 이 Mysql 을 사용 할 때 단일 표 데이터 의 양 이 너무 많아 서 조작 표 의 속도 가 느 려 지 는 해결 방법 은 바로 라 이브 러 리 분 표 입 니 다. 사실은 하나의 이치 입 니 다. 라 이브 러 리 분 표 도 이곳 의 Entry 원자 에 해당 합 니 다. hash 는 마치 하나의 Entry 원자 처럼 보 입 니 다.색인, 빨리 찾 아 주세요!
5. entry Set 방법 에 대하 여.
맵 은 맵 을 옮 겨 다 니 는 데 편리 하도록 entry Set 방법 을 제공 하여 하나의 Set 의 하위 클래스 로 전환 시 켰 습 니 다. 각 하위 클래스 에서 스스로 옮 겨 다 니 는 방법 을 실현 합 니 다. HashMap 의 경우 Entry [0] 부터 옮 겨 다 니 며 Entry [0] 라 는 링크 를 옮 겨 다 니 고 나 서 Entry [1] 를 옮 겨 다 니 는 것 과 유사 합 니 다. 2 차원 배열 이나.. 깊이 옮 겨 다 니 는 것 과 유사 합 니 다!
그 중 에 또 하나의 keyset 방법 도 entry set 방법 과 유사 하 며 내부 에서 만 key 를 entry 에서 분리 합 니 다.
마지막 으로 puutAll 방법 에 대해 서 는 puut 된 map 안의 내용 을 copy 또는 현재 map 에 덮어 쓰 고 그 전에 용량 계산 이나 확장 작업 을 하 며 마지막 으로 puut 방법 을 순환 적 으로 호출 합 니 다.
=======================================
자, 보 니 모두 자바 의 기반 이 었 습 니 다. 동생 은 이제... 고 개 를 돌려 이런 디자인 사상 을 보 는 것 도 재 미 있 었 습 니 다. 위 내용 은 개인 적 인 YY 가 많 았 습 니 다. 의견 이 다 르 면 아낌없이 가르쳐 주 셨 으 니 높 은 분 들 의 조언 을 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[백준 1411] 비슷한 단어 (JAVA)원본 알파벳이 숌하게 바뀔 경우, 이를 HashMap을 이용해서 쌍으로 묶어준다. HashMap 사용법이 익숙하지 못 해서 어려웠던 문제이다. HashMap 사용법 30분 💬 투포인터 버전 참고...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.