HashMap面試相關
阿新 • • 發佈:2018-12-12
HashMap面試相關整理
問題1:HashMap的基本原理和Hash衝突。
- 結構:鍵值對 Key,value 結構。陣列+連結串列
- 初始容量:static final int DEFAULT_INITIAL_CAPACITY = 16;
- 最大值 static final int MAXIMUM_CAPACITY = 1 << 30;
- 負載因子: static final float DEFAULT_LOAD_FACTOR = 0.75f;
- 父類: 繼承自AbstractMap<K,V> 實現介面Map<K,V>
- HashMap執行緒不安全,ConcurrentHashMap(Segment分段鎖)執行緒安全、效率高、HashTable(synchronized)執行緒安全、效率低。
- 允許NULL Key和Value
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
- 封裝一個實體類
package com.javaee.collections.map;
/**
*
* @Title: MapElement
* @Description: TODO(檢測Hash衝突)
* @author X-Dragon
* @version V1.0
*
*/
public class MapElement {
private int id;
private String name;
public MapElement() {
super();
}
public MapElement(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this .id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// @Override
// public int hashCode() {
// final int prime = 31;
// int result = 1;
// result = prime * result + id;
// result = prime * result + ((name == null) ? 0 : name.hashCode());
// return result;
// }
/**
*
* @Title: hashCode
* @Description: TODO(返回值都是1,用於測試Hash衝突)
* @return
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return 1;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MapElement other = (MapElement) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "MapElement [id=" + id + ", name=" + name + "]";
}
}
- 測試類
package com.javaee.collections.map;
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
HashMap<MapElement, String> map = new HashMap<MapElement, String>();
MapElement mapElement1 = new MapElement(1, "xielong1");//A 放入
MapElement mapElement2 = new MapElement(2, "xielong2");//B 放入
MapElement mapElement3 = new MapElement(2, "xielong2");//C 不放入
MapElement mapElement4 = new MapElement(2, "xielong4");//D 放入
if(mapElement1.hashCode()==mapElement2.hashCode()){
System.out.println("hashCode相等:");
}
map.put(mapElement1, mapElement1.getName());
map.put(mapElement2, mapElement2.getName());
map.put(mapElement3, mapElement3.getName());
map.put(mapElement4, mapElement4.getName());
map.put(null, null);//放入NULL
// map.put(null);//語法報錯
System.out.println(map.size());//包含NULL4個 不算NULL 三個
for(Map.Entry<MapElement, String> entry:map.entrySet()){//遍歷元素
System.out.println("Key:"+entry.getKey()+"Value:"+entry.getValue());
}
}
}
-
結論:
-
put方法
- 判斷是否可以放入MAP集合。首先判斷key的hashCode()是否衝突,不衝突直接放入。如果hashCode()一致,然後判斷equals()方法是否相等。如果equals()不相等,就根據Key的hashCode()找到對應的位置放入KEY衝突的資料。
- 當建立 HashMap 時,有一個預設的負載因子(load factor),其預設值為 0.75,這是時間和空間成本上一種折衷:增大負載因子可以減少 Hash 表(就是那個 Entry 陣列)所佔用的記憶體空間,但會增加查詢資料的時間開銷,而查詢是最頻繁的的操作(HashMap 的 get() 與 put() 方法都要用到查詢);減小負載因子會提高資料查詢的效能,但會增加 Hash 表所佔用的記憶體空間。
- equals()和hashCode()方法都要一起重寫。
-
get方法
-
根據Key找到對應的hashCode()方法找到bucket位置,然後獲取值物件。
-
如果兩個鍵的hashcode相同,當我們呼叫get()方法找到bucket位置之後,會呼叫keys.equals()方法去找到連結串列中正確的節點,最終找到要找的值物件。
-
許多情況下,面試者會在這個環節中出錯,因為他們混淆了hashCode()和equals()方法。因為在此之前hashCode()屢屢出現,而equals()方法僅僅在獲取值物件的時候才出現。一些優秀的開發者會指出使用不可變的、宣告作final的物件,並且採用合適的equals()和hashCode()方法的話,將會減少碰撞的發生,提高效率。不可變性使得能夠快取不同鍵的hashcode,這將提高整個獲取物件的速度,使用String,Interger這樣的wrapper類作為鍵是非常好的選擇。
-
-
HashMap怎麼進行動態擴容
- 擴容的方式是新建一個newTab,是oldTab的2倍。遍歷oldTab,將oldTab賦值進對應位置的newTab。與ArrayList中的擴容邏輯基本一致,只不過ArrayList是當前容量+(當前容量>>1)。
- JDK1.8使用了紅黑樹(自平衡二叉查詢樹)TreeMap相對複雜。
問題2:HashMap、HashTable、HashSet區別
- A:HashSet是set的一個實現類,hashMap是Map的一個實現類,同時hashMap是hashTable的替代品。
- HashMap執行緒不安全,允許空KEY和空VALUE,不允許放入一整個NULL,CurrentHashMap執行緒安全、效率高、HashTable執行緒安全、效率低、不允許放入任何空值。
- HashMap和Hashtable的區別
- 1 繼承和實現方式不同
- HashMap 繼承於AbstractMap,實現了Map、Cloneable、java.io.Serializable介面。
Hashtable 繼承於Dictionary,實現了Map、Cloneable、java.io.Serializable介面。
https://www.cnblogs.com/skywang12345/p/3311126.html - 2 HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。
- 3 Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個執行緒訪問Hashtable時,不需要自己為它的方法實現同步,而HashMap 就必須為之提供外同步。
Hashtable和HashMap採用的hash/rehash演算法都大概一樣,所以效能不會有很大的差異。 - 就HashMap與HashTable主要從三方面來說。
一.歷史原因:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map介面的一個實現
二.同步性:Hashtable是執行緒安全的,也就是說是同步的,而HashMap是執行緒序不安全的,不是同步的
三.值:只有HashMap可以讓你將空值作為一個表的條目的key或value