2.hash map和hash-table的区别

 我来答
ifeilong
推荐于2018-05-09 · TA获得超过8068个赞
知道大有可为答主
回答量:1187
采纳率:100%
帮助的人:782万
展开全部

第一个区别就先来说说继承关系吧

如果你baidu一下,会发现网上的大致说法与“由于Java发展的历史原因。Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。”相同。

这种说法没有错,但是不够准确,特别是对于我们这种大众菜鸟来说,如果不去深究的话,可能就会造成一些理解上的差异。简单的认为Hashtable没有继承Map接口。 


我们可以参考一下最新的JDK1.6的源码,看看这两个类的定义:


public class Hashtable<K,V>extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable {…}
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {…}


可以看到hashtable也是继承了Map接口。 


它们的不同是Hashtable(since JDK1.0)就继承了Dictionary这个抽象类,

HashMap(since JDK1.2)继承的则是AbstractMap这个抽象类。


第二个区别我们从同步和并发性上来说说它们两个的不同。


可以通过这两个类得源码来分析,Hashtable中的主要方法都做了同步处理,而HashMap则没有。 


可以说Hashtable在默认情况支持同步,而HashMap在默认情况下是不支持的。 


我们在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。 


对HashMap的同步处理可以使用Collections类提供的synchronizedMap静态方法;


或者直接使用JDK5.0之后提供的java.util.concurrent包里的ConcurrentHashMap类。



第三个区别就是它们对于null值的处理方式了。



我们依然能够从源代码中得知,Hashtable中,key和value都不允许出现null值。


 


public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash =
key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
//…
}


  


在我们使用上面的方法时,

如参数value为null,可以从代码中直接看出程序会抛出NullPointerException;

而在key为null时,则会在“int hash =
key.hashCode();“这段计算Hash值的过程中抛出NullPointerException。


 


而在在HashMap中,允许null作为key存在,并且和其他key的特性一样,这样的null值key只能有一个;


另外HashMap允许多个value为null。


 


这样大家就要注意了, HashMap中就不能用get(key)方法来判断HashMap中是否存在某个key,因为value为null和不存在该key的Entry都会返回null值,而应该用containsKey()方法来判断了。


 


import
java.util.HashMap;
import java.util.Map;
import
java.util.Map.Entry;
public class TestCase
{
 
public static void main(String[] args) {
Map<Integer,String>
hashMap = new HashMap<Integer,String>();
hashMap.put(0, null);
hashMap.put(1,
"one");
hashMap.put(2,
"two");
hashMap.put(null,
"null");
for(Entry<Integer,
String> e : hashMap.entrySet()) {
System.out.println("Key:
" + e.getKey() + " -- Value: " + e.getValue());
}
System.out.println(hashMap.get(0));
System.out.println(hashMap.get(4));
System.out.println("Contains
key 0 ? :" + hashMap.containsKey(0));
System.out.println("Contains
key 4 ? :" + hashMap.containsKey(4));
System.out.println("Contains
value null ? :" + hashMap.containsValue(null));
}
}


 


结果:


 


Key: null -- Value:
null
Key: 0 -- Value: null
Key: 1 -- Value: one
Key: 2 -- Value: two
null
null
Contains key 0 ? :true
Contains key 4 ?
:false
Contains value null ?
:true




第四个不同就是它们两个Hash值的获取方式了。


还是通过源代码源代码,Hashtable是直接使用key对象的hash值。


 


 


public synchronized V put(K key, V value) {
// Make sure the value is not null 
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = key.hashCode();//hashcode
int index = (hash & 0x7FFFFFFF) % tab.length;
//…
}

而HashMap则是利用key对象的hash值重新计算一个新的hash值。 


 
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
 
int hash= hash(key.hashCode());//hashcode
int i = indexFor(hash, table.length);
//…
}
 
static int hash(int h)
{
h ^=(h >>> 20) ^ (h >>> 12);
returnh ^ (h >>> 7) ^ (h >>> 4);
}

 


第五个不同就是Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。


HashMap中内部数组的初始容量是16, 加载因子为0.75,而且数组容量增容后也要是2指数次幂:

 

 


/**
* The default
initial capacity - MUST be a power of two.
*/
static final int
DEFAULT_INITIAL_CAPACITY = 16;
 
/**
* The load factor
used when none specified in constructor.
*/
static final float
DEFAULT_LOAD_FACTOR = 0.75f;

 

 

HashTable中的内部数组的初始容量是11,加载因子也是0.75数组的增容方式为(oldCapacity * 2 + 1):

 

 


public Hashtable() {
this(11,
0.75f);
}
 
protected void
rehash() {
int
oldCapacity = table.length;
Entry[]
oldMap = table;
int
newCapacity = oldCapacity * 2 + 1;
//…
}


第六个不同我们从它们两个遍历方式的内部实现上来说。


Hashtable HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。


第七个不同时它们的拷贝构造函数的不同。


依然是通过查看源码,可以发现它们两个对于拷贝函数初始容量的不同值。

HashMap的实现是: 

 

public
HashMap(Map<? extends K, ? extends V> m) {
this(Math.max((int)
(m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
putAllForCreate(m);
}

 

而Hashtable的实现是:

 

public
Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(),
11), 0.75f);
putAll(t);
}
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式