자바 기반 HashMap 의 capacity 와 loadFactor 상세 설명
9497 단어 Java
내 가 개발 에서 가장 많이 쓴 HashMap 성명 은 Map map=new HashMap()이다.다 들 그런 건 지 모 르 겠 지만만약 당신 이 아래 두 가지 라면:
//
Map map = new HashMap(int initialCapacity);
//
Map map = new HashMap(int initialCapacity, float loadFactor);
나 는 네가 용량 과 로드 인자 에 대해 이해 하고 있다 고 믿는다.
결국 우리 의 HashMap 은 하나의 용기 이 고 그 안에 key-value 를 넣 었 을 뿐 입 니 다.map 는 동적 용기(즉 용량 이 고정 되 지 않 은 것)입 니 다.용량 이 고정 되 지 않 은 이상 얼마 입 니까?무한대 인가요?여러분 들 은 이런 문 제 를 생각해 본 적 이 있 는 지 모 르 겠 습 니 다.이것 은 로 딩 인자 와 용량 두 가지 에 관련된다.
우리 그냥 소스 로 올 려 보 자.맵 에 용량 이 있다 는 것 은 크기 의 구분 이 있다 는 것 을 설명 한다.그러면 우리 맵 의 크기 가 얼마 인지 원본 코드 에서 어떻게 말 하 는 지 알 아 보 자.우리 가 정상적으로 맵 을 사용 하 는 절 차 는:
//
Map map = new HashMap();
// put
map.put("key", "value");
1:맵 초기 화
/**
* Constructs an empty HashMap with the default initial capacity
* (16) and the default load factor (0.75).
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
// , loadFactor( ),
// , ,
2:map.put 가 포인트 입 니 다.put 방법 을 보 러 가 겠 습 니 다.
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with key, or
* null if there was no mapping for key.
* (A null return can also indicate that the map
* previously associated null with key.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
// put ( )
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node[] tab; Node p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
// , return, ,
return oldValue;
}
// if, key , value
// ,
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
다음은 맵 확장 코드 를 붙 여 구체 적 으로 말씀 드 리 겠 습 니 다.
// size > threshold resize
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
// map key ,
// :
// ++modCount;
// map
// if (++size > threshold) {
// resize();
// }
//
// , size ?threshold ? ,
// resize() , resize()
// resize()
// : ( )
// put resize ( ), ,
// threshold = newThr;
// if else, threshold
// , oldCap( map table , table
// null,oldCap 0)
// oldCap 0
// newCap = DEFAULT_INITIAL_CAPACITY; 16
// newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
// newThr resize : * = 16 * 0.75 = 12
// map size 12 , resize( )
// map ,
// , , ,16 32 64......
// : map
final Node[] resize() {
Node[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
// : ( )
// : map ,
@SuppressWarnings({"rawtypes","unchecked"})
Node[] newTab = (Node[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode)e).split(this, newTab, j, oldCap);
else { // preserve order
Node loHead = null, loTail = null;
Node hiHead = null, hiTail = null;
Node next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
그래서 여러분 보 셨 죠?맵 동태 의 원 리 를 보 셨 죠?사실 그 에 게 도 용량 이 있 습 니 다.
그러면 맵 의 특징 과 원 리 를 간단하게 정리 합 니 다.
1.map 는 먼저 배열 과 링크 의 데이터 구 조 를 결합 시 키 고 배열 의 기본 길 이 는 16(즉,기본 용량)이다.
2.map 에서 put 를 진행 할 때 같은 key 가 있 으 면 새 value 는 오래된 value 를 교체 하고 오래된 value 로 돌아 갑 니 다.그렇지 않 으 면 링크 를 삽입 하고 null,size+를 되 돌려 줍 니 다.
3.map 의 확장,첫 번 째 는 기본 용량(16),기본 확장 한계 값(16*0.75=12)입 니 다.만약 size 가 12 에 이 르 렀 을 때 다음 확장 을 진행 하면 용량 과 극한 치 는 모두 원래 의 두 배,32,24 로 확대 된다.64,48.....................................................................CAPACITY=1<<30,확장 임계값 threshold=Integer.MAXVALUE
마지막 으로 질문 을 던 집 니 다.인터넷 에 서 는 왜 맵 의 기본 로드 인자 가 0.75 인지 말 하고 있 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.