背景
面试官:说一下HashMap和Hashtable的区别吧?
面试者:1. HashMap是线程非安全的,Hashtable是线程安全的
2.HashMap比HashTable快
3.Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
面试官:HashMap是否支持null Key,null value?HashTable是否支持null Key,null value?
面试者:HashMap支持null key和null value,HashTable也支持null key和null value
面试官:为什么?
面试者:规定的
面试者内心:崩溃!我也不知道为什么!上面都是面试题背的。
面试官:回去等通知吧
上面的面试场景你是否经历过?这个问题也许会伤到很多面试者的心,那我们扒出来这两个的源码来细细看看!
HashMap为什么支持null键值?
1.我们知道HashMap的可以要做Hash处理的过程:
/**
* Computes key.hashCode() and spreads (XORs) higher bits of hash
* to lower. Because the table uses power-of-two masking, sets of
* hashes that vary only in bits above the current mask will
* always collide. (Among known examples are sets of Float keys
* holding consecutive whole numbers in small tables.) So we
* apply a transform that spreads the impact of higher bits
* downward. There is a tradeoff between speed, utility, and
* quality of bit-spreading. Because many common sets of hashes
* are already reasonably distributed (so don't benefit from
* spreading), and because we use trees to handle large sets of
* collisions in bins, we just XOR some shifted bits in the
* cheapest possible way to reduce systematic lossage, as well as
* to incorporate impact of the highest bits that would otherwise
* never be used in index calculations because of table bounds.
*/
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
当key为null时,将key的值置为0计算
-
Hashcode
值得分布情况:
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
/**
* Returns the hash code of a non-{@code null} argument and 0 for
* a {@code null} argument.
*
* @param o an object
* @return the hash code of a non-{@code null} argument and 0 for
* a {@code null} argument
* @see Object#hashCode
*/
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
当value为null时,默认为0
HashTable为什么不支持null键值
1.key不能为null,否则报空指针异常
/**
* Tests if some key maps into the specified value in this hashtable.
* This operation is more expensive than the {@link #containsKey
* containsKey} method.
*
* <p>Note that this method is identical in functionality to
* {@link #containsValue containsValue}, (which is part of the
* {@link Map} interface in the collections framework).
*
* @param value a value to search for
* @return <code>true</code> if and only if some key maps to the
* <code>value</code> argument in this hashtable as
* determined by the <tt>equals</tt> method;
* <code>false</code> otherwise.
* @exception NullPointerException if the value is <code>null</code>
*/
public synchronized boolean contains(Object value) {
if (value == null) {
throw new NullPointerException();
}
Entry<?,?> tab[] = table;
for (int i = tab.length ; i-- > 0 ;) {
for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
if (e.value.equals(value)) {
return true;
}
}
}
return false;
}
2.value不能为null,否则报空指针异常
/**
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashtable. Neither the key nor the
* value can be <code>null</code>. <p>
*
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @param key the hashtable key
* @param value the value
* @return the previous value of the specified key in this hashtable,
* or <code>null</code> if it did not have one
* @exception NullPointerException if the key or value is
* <code>null</code>
* @see Object#equals(Object)
* @see #get(Object)
*/
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;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
jdk 为什么这么设计?
jdk的设计为什么没有保持一致?
首先,我们看一下HashTable
/ * @author Arthur van Hoff
* @author Josh Bloch
* @author Neal Gafter
* @since JDK1.0
*/
它是jdk1.0的第一个版本出现的,主要设计者是Arthur van Hoff,也许设计者当时认为null作为key 和value 是没有什么用的。
再看一下HashMap的情况
/ * @author Doug Lea
* @author Josh Bloch
* @author Arthur van Hoff
* @author Neal Gafter
* @since 1.2
*/
它是直到jdk 1.2 才出现,主要设计者是大名鼎鼎的Doug Lea,实际项目中,真的是有value为null的情况的。key为null的情况比较少见,但不代表没有。HashMap允许null为key和value应当是类的设计者思考让这个类更有用的设计吧!