java.util.Hashtable

정의
           public class Hashtable
           extends Dictionary
           implements Map,Cloneable, Serializable
이것은 키를 상응하는 값에 비추는 해시표를 실현합니다.null이 아닌 모든 대상은 키나 값으로 사용할 수 있습니다.해시 테이블에 대상을 성공적으로 저장하고 얻기 위해서는 키의 대상이hashCode 방법과 equals 방법을 실현해야 합니다.
Hashtable의 실례는 두 가지 파라미터가 그 성능에 영향을 미친다. 초기 용량과 불러오는 인자이다.용량은 해시표에 있는 통의 수량이며, 초기 용량은 해시표가 만들어졌을 때의 용량이다.주의, 해시표의 상태는 오픈입니다. '해시 충돌' 이 발생할 경우, 한 통에 여러 항목을 저장하고, 이 항목들은 순서대로 검색해야 합니다.캐리어 인자는 해시표가 용량이 자동으로 증가하기 전에 얼마나 가득 채울 수 있는지에 대한 척도이다.초기 용량과 마운트 인자 두 파라미터는 이 실현에 대한 알림일 뿐입니다.언제, 그리고 Rehash 방법을 호출할지 여부에 대한 구체적인 세부 사항은 이 실현에 의존한다.
일반적으로 기본 로드 인자 (0.75) 는 시간과 공간 비용에 있어서 절충을 찾습니다.로드 인자가 너무 높으면 공간 비용이 줄어들지만, 항목을 찾는 시간도 증가합니다. (대부분의 Hashtable 작업에서 get과put 작업을 포함하여 이 점을 반영합니다.)
초기 용량은 주로 공간 소모와rehash 조작을 수행하는 데 필요한 시간 손실 사이의 균형을 제어한다.만약 초기 용량이Hashtable에 포함된 최대 항목 수보다 크면, 불러오는 인자를 나누면,rehash 작업이 영원히 일어나지 않습니다.그러나 초기 용량을 너무 높게 설정하면 공간이 낭비될 수 있습니다.
만약 많은 항목이Hashtable에 저장된다면, 필요에 따라 자동rehashing 조작을 실행하여 테이블의 용량을 늘리는 방법에 비해, 충분한 초기 용량으로 해시표를 만드는 것이 항목을 삽입하는 데 더욱 효과적일 수 있습니다.
다음 예는 숫자의 해시표를 만들었다.숫자 이름을 키로 사용합니다.
           Hashtable numbers= new Hashtable();
           numbers.put("one", 1);
           numbers.put("two", 2);
           numbers.put("three", 3);
숫자를 가져오려면 다음 코드를 사용합니다.
          Integer n = numbers.get("two");
          if (n!= null) {
                 System.out.println("two= "+ n);
          }
모든 종류의'collection 보기 방법'에서 되돌아오는 collection의iterator 방법으로 되돌아오는 교체기는 빠르게 실패합니다. Iterator를 만든 후에 구조적으로Hashtable를 수정하면 Iterator 자체의remove 방법을 사용하지 않으면 언제든지 어떤 방식으로든 수정할 수 있습니다. Iterator는 Concurrent Modification Exception을 던집니다.따라서 동시 수정에 직면하면 Iterator는 곧 완전히 실패할 것이며, 장래의 어떤 불확정한 시간에 임의의 불확정 행위가 발생할 위험을 무릅쓰지 않을 것이다.Hashtable의 키와 요소 방법으로 되돌아오는 Enumeration은 빠르게 실패하지 않습니다.
교체기의 빠른 실패 행위는 보장할 수 없습니다. 일반적으로 동기화되지 않은 수정이 발생했는지 여부에 대해 어떠한 경직된 보장도 할 수 없기 때문입니다.빠른 실패 교체기는 최선을 다해 Concurrent Modification Exception을 던집니다.따라서 이러한 교체기의 정확성을 높이기 위해 이 이상에 의존하는 프로그램을 작성하는 것은 잘못된 방법이다. 교체기의 빠른 실패 행위는 프로그램 오류를 감지하는 데만 사용해야 한다.   Hashtable는 동기화됩니다.
구조 방법   Hashtable()는 기본 초기 용량(11)과 부하 인자(0.75)로 새로운 빈 해시표를 만들었다.   Hashtable(int initialCapacity)는 초기 용량과 기본 부하 인자(0.75)를 지정하여 새로운 빈 해시표를 구성합니다.   Hashtable(int initialCapacity,float loadFactor)는 지정한 초기 용량과 지정한 부하 인자로 새로운 빈 해시 테이블을 구성한다.   Hashtable (MapK ,?extendsV>t)는 주어진 맵과 같은 매핑 관계를 가진 새 해시 테이블을 구성합니다.
구조 함수 소스 코드:
public Hashtable(int initialCapacity, float loadFactor) {  
//      
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); 

//        
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal Load: "+loadFactor);

if (initialCapacity==0)
initialCapacity = 1;

this.loadFactor = loadFactor;

//   table,     initialCapacity table   
table = new Entry[initialCapacity];
//    
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); 
//   HashSeed 
initHashSeedAsNeeded(initialCapacity);
} 

주요 방법
우선 put 방법을 봅시다. 지정한 key 을 이 해시표의 지정한 value 에 비추겠습니다.키와 값value를 비울 수 없습니다.
public synchronized V put(K key, V value) {  
//   value  null  
if (value == null) {  
throw new NullPointerException();  
}
  
//   key table[]      
//     : 
// 1、  key hash ,   table[]      
// 2、  index    ,                 key,    value,    
Entry tab[] = table;
int hash = hash(key);    //  key hash 
int index = (hash & 0x7FFFFFFF) % tab.length;     //   key     
//  ,   key,  
for (Entry e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) {
V old = e.value;
e.value = value;
return old;
}
}
 
modCount++;
//                 ,       
if (count >= threshold) {
rehash();
tab = table;
hash = hash(key);
index = (hash & 0x7FFFFFFF) % tab.length;
}
 
//               
Entry e = tab[index];
tab[index] = new Entry<>(hash, key, value, e);
//      +1
count++;
return null;
}

put 방법의 전체 처리 절차는 키의hash값을 계산하고hash값에 따라 키가 테이블 그룹에 있는 인덱스 위치를 얻은 다음에 키에 있는 Entry 체인 테이블을 교체합니다. 이 체인 테이블에 키 대상이 존재하면 바로value값을 바꾸면 됩니다. 그렇지 않으면 키-value 노드를 index 인덱스 위치에 삽입하십시오.
put 방법에서 Table[]에 Entry 요소를 추가하려면 먼저 용량 검사를 하고 용량이 밸브값에 도달하면 HashTable는 확장 처리 Rehash()를 한다. 다음과 같다.
protected void rehash() {
int oldCapacity = table.length;
//   
Entry[] oldMap = table;
 
//     =     * 2 + 1
int newCapacity = (oldCapacity << 1) +1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
return;
newCapacity = MAX_ARRAY_SIZE;
}
 
//     size = newCapacity  HashTable
Entry[] newMap = new Entry[];
 
modCount++;
//       
threshold = (int)Math.min(newCapacity *loadFactor, MAX_ARRAY_SIZE + 1);
//     hashSeed
boolean rehash =initHashSeedAsNeeded(newCapacity);
 
table = newMap;
//            HashTable 
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry old = oldMap[i] ; old!= null ; ) {
Entry e = old;
old = old.next;
 
if (rehash) {
e.hash = hash(e.key);
}
int index = (e.hash & 0x7FFFFFFF) %newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}

put 방법에 비해 get 방법은 비교적 간단할 것이다. 처리 과정은 키의hash값을 계산하고 테이블 그룹에 있는 인덱스 위치를 판단한 다음에 체인 테이블을 교체해서 키에 대응하는value를 찾을 때까지 일치하는 것이다. 만약null로 되돌아오는 것을 찾지 못했다면.
public synchronized Vget(Object key) {
Entry tab[] = table;
int hash = hash(key);
int index = (hash & 0x7FFFFFFF) %tab.length;
for (Entry e = tab[index] ; e !=null ; e = e.next) {
if ((e.hash == hash)&& e.key.equals(key)) {
return e.value;
}
}
return null;
}

Hashtable과 HashMap의 차이
첫째: 우리는 그들의 정의를 통해 그들의 차이를 알 수 있다. Hashtable은Dictionary류를 바탕으로 하고 HashMap은AbstractMap을 바탕으로 한다.Dictionary는 무엇입니까?이것은 키를 상응하는 값에 비추는 모든 종류의 추상적인 부류이며, AbstractMap은 맵 인터페이스를 기반으로 하는 핵심 구현으로 이 인터페이스를 실현하는 데 필요한 작업을 최대한 줄인다.
둘째:HashMap은null의 키와 임의의null의value가 존재할 수 있지만,Hashtable의 키와value는null이 허용되지 않습니다.HashMap이null인 키를 만났을 때,putForNullKey 방법을 사용해서 처리합니다.value는 대상이라면 아무 처리도 하지 않습니다.
셋째:Hashtable의 방법은 동기화되는 것이지만HashMap의 방법은 그렇지 않다.그래서 어떤 사람들은 일반적으로 다중 스레드 동기화와 관련이 있을 때Hashtable을 사용하고 관련이 없으면 HashMap을 사용하라고 권장하지만 Collections 클래스에는 정적 방법이 존재한다.synchronizedMap (). 이 방법은 안전한 스레드 맵 대상을 만들고 이를 봉인된 대상으로 되돌려주기 때문에 Collections 클래스의synchronizedMap 방법을 통해 잠재적인 HashMap에 동시 접근할 수 있다.

좋은 웹페이지 즐겨찾기