크기 조정의 자동 확장을 해시 맵

학습 조건이 레드 - 블랙 트리의 지식을 트리거하기 전에의 HashMap에서, 스텝 크기 조정 (), 지식의이 작품을 봐 와서이있다

HashMap에 너무 접근의 최고 효율을 달성 할 수있는, 내부 해시 테이블에 의해, 키의 형태로 데이터를 저장하기위한 JAVA,이 키 값의 가장 일반적인 세트 중 하나 인 경우 O (1)의 실 사용 그 효율은 최악의보다 낮은되지 않도록 연결리스트와 레드 - 블랙 트리 구조를 도입 해시 충돌이있을 수 있습니다 O (logn).

컬렉션 기초하는 것은 어레이를 기반으로, 링크 된리스트 데이터 구조와 같은베이스, 수거 용량이 불충분하고, 동적 확장은 충분한 공간이 데이터를 저장하도록 존재하도록 트리거 데이터가 실제로 조정 등 복사 포함 같은 동적 범위 확장, 귀찮고 시간이 소요되는 작업이며, 그 추정 및 사용 데이터 량 합리적 설계 방법에 의해, 지정된 세트의 초기 용량은, 다음 동작을 트리거 동적 전개를 보장하지 않을 수있다.

HashMap의 초기화시에 살펴 보자는 한 무슨 일

/ ** 
* 구축합니다가 빈 <TT> HashMap의 </ TT> 초기 지정된
* 기본 부하 및 용량 계수 (0.75).
*
파라미터 : 파라미터 : initialCapacity 초기 용량.
*는 IF가 음수는 IllegalArgumentException 초기 용량 @throws.
* /
공용 HashMap의 (INT의 파라미터 : initialCapacity) {
이 본 (파라미터 : initialCapacity, DEFAULT_LOAD_FACTOR)
}

HashMap의이 부하율 생성자 지정된 초기 용량의 구성을위한 방법은, 내부이 방법은 실제로 다른 구성 방법에 대한 호출 인 제공 디폴트의 부하 계수는 0.75이다
/ ** 
* 지정된 초기 구축과 <TT>의 HashMap </ TT> 빈
* 용량 및 부하율.
*
* @param 파라미터 : initialCapacity 초기 용량
파라미터 : loadFactor 부하율이
초기 용량이 부의 경우 *, IllegalArgumentException를 @throws
*가 부하 계수가 정이 아닌
* /
{(파라미터 : initialCapacity 플로트 loadFactor INT) 공공의 HashMap
경우 (파라미터 : initialCapacity <0)
( "잘못된 초기 용량 :"+ 새, IllegalArgumentException를 throw
파라미터 : initialCapacity);
(파라미터 : initialCapacity> MAXIMUM_CAPACITY 있으면)
파라미터 : initialCapacity = MAXIMUM_CAPACITY;
경우 (loadFactor <= 0 || Float.isNaN (loadFactor))
새로운 IllegalArgumentException가 ( "잘못된 부하율 :"+ 던져
loadFactor을);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor (파라미터 : initialCapacity);
}

임계치는 트리거 임계 HashMap의 확장을 저장하는데 사용되며, 즉, 요소의 수는 해시 맵에 도달 액에 저장 될 때, 자동 확장을 유발

상기 방법은 HashMap의 초기화, 수신 파라미터 : initialCapacity에서 알 수있는 바와 같이, 직접적으로 사용될 수 있지만 후의 값 임계 후의 처리 방법 tableSizeFor ()

이 방법의 처리 로직에서 살펴 보자 :

/ ** 
. * (A)의 전원 TWO 용량 대상 크기 GIVEN 리턴
* /
정적 INT tableSizeFor 최종 INT (CAP) {
= INT N-CAP - 1].
N- | = N - >>> 1].
N- | = N - >>> 2]
. N- | = N - >>> 4]
N- | = N - >>> 8].
N- | = N - >>> 16;
창 (N- <0) 1 : (N -.> = MAXIMUM_CAPACITY) MAXIMUM_CAPACITY : N- + 1.? ;
}

이렇게하는 목적으로, 2 이렇게 얻어진 리턴 값이 항상 유지되는 N 번째 전력 사실 점차적 비트 연산을 볼 수있는 것은 후속 팽창되어, 팽창 새로운 테이블의 빠른 계산 데이터 위치
외부 번호 다음 계산 한 후, 10000 예를 들어 순수, 팽창하지 않고, 데이터가 저장 될 수있는 최소 전력 = 기본 부하율 0.75f 곱한 163 842 14해질 것이다 양이다
16384 * 0.75 = 12288 
팽창 할 때 초기화되는 HashMap 10,000의 수신 능력, 스토리지 10000 데이터의 실제 양이 자동으로 트리거되지 않도록

시나리오 다음 다른 종류, 우리는 (1000)의 초기 용량을 전달 상황 지금 좋아? 다시 분석 :
HashMap의 구성 방법은, 상기 임계 값의 확장은 너무 초기 수신 1,000이면 생성자를 산출 한 생성자 tableSizeFor에 직접 할당 방법에 의해 계산 Threhold을 가지고
threhold 1024하지만, 그 당시 않았다 직접 HashMap의 사용, 부하율 때의 HashMap의 처리 로직에 모습을이 매개 변수를 사용하는 아무 소용이 없다이 시간 :
/ ** 
* 이물질 Map.put 및 관련 방법.
*
키 * @param 해시 해시
파라미터 : 키 키
* @param 값을 넣어 값
* @param onlyIfAbsent true의 경우, 기존의 값을 변경하지 않는
거짓이, 테이블 작성 모드에서 파라미터 : EVICT 경우입니다.
* @return 이전 값 경우는 null
* /
최종 V putVal (INT 해시 키 K, V 값 부울 onlyIfAbsent,
부울 EVICT) {
기지국 <K, V> [] 탭; 노드 <K, V> P; INT의 N, I;
경우 ((TAB = 테이블) == 널 || (N = tab.length) == 0)
N = (TAB = 리사이즈 ())의 길이.;
((p = 탭 [내가 = (N - 1) 해시]) == NULL) 경우
탭 [I] = newNode (해시 키 값을 널 (NULL));
다른 {
노드 <K, V> E; K의 K;
경우 (p.hash == 해시 &&
((K = p.key) == 키 || (키 = NULL && key.equals (K)))!)
E = P;
다른 경우 (p instanceof를 TreeNode에)
E = ((TreeNode를 <K, V>) p) .putTreeVal (이 탭, 해시 키 값);
또 {
대 (INT binCount = 0; binCount ++) {
경우 ((E = p.next) == NULL) {
p.next = newNode (해시 키 값, NULL);
경우 (binCount> = TREEIFY_THRESHOLD 1 -) // -1 대 1
treeifyBin (탭, 해시);
단절;
}
경우 (e.hash == 해시 &&
(! (K = e.key) == 키 || (키 = NULL && key.equals (K))))
체류;
p = E;
}
}
경우 (예 = 널!) {// 키에 대한 매핑 기존의
V를 oldValue입니다 = e.value;
경우 (onlyIfAbsent || oldValue입니다 == 널!)
e.value = 값;
afterNodeAccess (E);
oldValue입니다를 반환;
}
}
++의 modCount;
경우 (++ 크기> 임계 값)
크기 조정 ();
afterNodeInsertion (EVICT);
NULL을 반환;
}

HashMap의, 모든 데이터 jdk1.8 후, 테이블 형식 조정 ,, 내부 배열 멤버 변수 테이블에 저장되어 있지만, 배열의 기본 구성을 변경하지 않고, 세 사이의 관계는 다음
표 크기는 = 임계 * loadFactor
의 HashMap에서이 테이블도 즉, 크기 조정 논리있어서 만, 동적 확장 부담도 초기화 테이블 베어, 크기 조정 프로세스를 초기화하고, 상기 소스 코드, 그것을 알 수있다 우리는 제 때에
볼 테이블 널인 경우 데이터를 저장하는 방법을 넣고, 리사이즈를 초기화하기 위해 호출 될 때 호출, 임계 값, 초기화의 완료를 조정하는 방법을 변경 :
/ ** 
*를 초기화 또는 복식 테이블 크기. 널 경우에 할당
의 초기 용량과 목표 * 어코드 필드 임계 유지.
* 그렇지 않으면, 우리는 전력의-두 개의 확장은 사용하고 있기 때문에
같은 인덱스, 또는 이동에서 각각의 빈해야 하나 숙박에서 * 요소
새 테이블 오프셋 2의 거듭 제곱으로 *을.
*
* 표 @return
* /
최종 노드 <K, V> [] 리사이즈 () {
기지국 <K, V>를 [] = oldTab 테이블;
INT oldCap = (oldTab == NULL)? 0 : oldTab.length;
INT oldThr = 임계;
INT newCap, newThr = 0;
경우 (oldCap> 0) {
경우 (oldCap> = MAXIMUM_CAPACITY) {
임계치는 Integer.MAX_VALUE =;
oldTab를 반환;
}
다른 경우 ((newCap = oldCap << 1) <MAXIMUM_CAPACITY &&
oldCap> = DEFAULT_INITIAL_CAPACITY)
newThr oldThr << = 1; // 두 임계
}
다른 경우 (oldThr> 0) // 초기 용량이 임계 값에 넣었다
newCap = oldThr;
기본값을 사용하여 다른 {// 제로 초기 임계 의미
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (INT) (* DEFAULT_LOAD_FACTOR DEFAULT_INITIAL_CAPACITY);
}
경우 (newThr == 0) {
플로트 피트 = (플로트) newCap * loadFactor;
newThr = (newCap <MAXIMUM_CAPACITY && 피트 <(플로트) MAXIMUM_CAPACITY?
(INT) 피트 : 정수.
}
임계치는 newThr =;
@SuppressWarnings ({ "rawtypes", "체크"})
노드 <K, V> [] newTab = (노드 <K, V> []) 새로운 노드 [newCap];
테이블을 newTab =;
만약 (! oldTab = NULL) {
대 (INT J = 0; J <oldCap, J ++) {
기지국 <K, V> E;
경우 ((E = oldTab [J])! = NULL) {
oldTab [J] = NULL;
경우 (e.next == NULL)
newTab [e.hash 및 (newCap - 1)] = E;
다른 경우 (TreeNode를 instanceof를 E)
((TreeNode를 <K, V>) E) .split (이, newTab, J, oldCap);
또 {// 순서를 유지
노드 <K, V> loHead = NULL, loTail = NULL;
노드 <K, V> hiHead = NULL, hiTail = NULL;
노드 <K, V> 다음;
할 {
다음 = e.next;
((e.hash 및 oldCap) == 0) {만약
있다면 (loTail == NULL)
loHead = E;
다른
loTail.next = E;
loTail = E;
}
다른 {
경우 (hiTail == NULL)
hiHead = E;
다른
hiTail.next = E;
E = hiTail;
}
}을 잠시 (! (E = NEXT) = NULL)
IF {(loTail = NULL!)
loTail.next = NULL;
newtab [J] = loHead;
}
(! hiTail = NULL) {IF
hiTail. 다음 = 널;
newtab [J + OLDCAP =는 hiHead;
}
}
}
}
}
리턴 newtab;
}

우리는 초기 용량을 지정하고, 테이블이 초기화되지 않은 경우, threshol 할당하여 (팽창 액 대신에) 시간 oldThr는 아니다 0, OLDCAP = 0 (테이블 용량), 논리가 갈 것 때문에 :
다른 (oldThr> 0) // 초기 용량 임계 값에 추가 된 경우에는 
newCap = oldThr,

그것은 oldThr 우리는 HashMap의 값의 용량을 빌드 할 때 새로 만든 테이블이 지정 될 것이다 newCap에 할당됩니다
다음 아래로 이동
경우 (newThr == 0) { 
플로트 피트 = (플로트) newCap * loadFactor;
newThr = (newCap <MAXIMUM_CAPACITY && 피트 <(플로트) MAXIMUM_CAPACITY?
(INT) 피트 : Integer.MAX_VALUE로);
}
임계치는 newThr =;
노드 <K, V> [] newTab = (노드 <K, V> []) 새로운 노드 [newCap]; 
테이블을 newTab =;


newThr = 0 loadFactor 새로운 임계 값의 부하율에 의해 조정하고, loadFactor가 임계치에 저장 newCap하여 새로운 배열을 생성하여 조정 한 후 마지막으로 상기 임계 값을 이용하며, 전체 테이블 초기화 테이블에 할당한다
재 초기화 그렇게 파라미터 : initialCapacity 통과시 동작이 임계치에 할당 된 비트했으나 실제로 테이블의 크기이며, 결국 loadFactor하여 임계 값을 조정 재
입사 초기 1,000 용량이지만 팽창의 임계 값에 따른 테이블 어레이 1000 때 상기 크기 조정 1024 * 0.75 = 768로 조정한다
용량 부족, 또는 자동 팽창을 트리거 할 때, 데이터 (1000)에 기억하므로

비즈니스가 자동 확장을 방지하기 위해, 언제 초기화 할 때 때 실제 용량 우리가 기대되면 용량 값이 초기 용량이 얻어지는 0.75로 나눈.

HashMap의 디폴트의 초기 용량은 16입니다.

착신 10000, 치수 산출 후 threshols 후 16384 12288 * 0.75 = 10,000 저장된 데이터 때문에 자동 확장을 실행하지 않을 때 조건은 처음



 

추천

출처www.cnblogs.com/wangflower/p/12236481.html