int index = X.hashCode()
1) 먼저, 미리정의된 객체(key)의 HashCode함수와 해쉬 버켓의 크기(N)를 활용하여 key에 대한 해시값을 구한다.
int index = key.hashCode() % N
2) index값에 해당하는 배열에 위치에 접근하여 데이터를 추가하는데 만약 해당위치에 이미 데이터가 있다면 해당위치에 데이터를 추가할 수 없으므로 해당 위치데이터의 링크드리스트를 따라가면서 자신의 key값과 같은 데이터가 있다면 덮어씌우고 없다면 다음으로 계속 이동하면서 같은 데이터를 발견하지 못했을 경우 마지막에 데이터를 추가한다.
transient Node<K,V>[] table;
//해쉬 버켓배열
transient int size;
//저장된 Node 요소의 개수
int threshold;
//해시 테이블 재구축 기준
final float loadFactor;
//해시 테이블 재구축 기준 비율
transient int modCount;
//해시 테이블 재구축 회수
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
// aka 16, 기본 해쉬 버켓의 개수
static final int MAXIMUM_CAPACITY = 1 << 30;
// 최대 해쉬버켓의 개수, 2^30
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 기본 load_factor
static final int TREEIFY_THRESHOLD = 8;
//기본 링크드리스트를 트리로 변환할 기준
// 한 해쉬 버켓에 연결된 노드의 개수가
//이 기준을 넘어가면 트리로 만듬 레드블랙트리로 만들어짐.
// 인자로 사용하는 newCapacity는 언제나 2a이다.
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
// MAXIMIM_CAPACITY는 230이다.
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
// 새 해시 버킷을 생성한 다음 기존의 모든 키-값 데이터들을
// 새 해시 버킷에 저장한다.
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
// 모든 해시 버킷을 순회하면서
for (Entry<K,V> e : table) {
// 각 해시 버킷에 있는 링크드 리스트를 순회하면서
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
// 해시 버킷 개수가 변경되었기 때문에
// index 값(hashCode % M)을 다시 계산해야 한다.
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }