力爭清晰完整准確
1、String類為什么是final的
首先分析String的源碼:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];
- 類被final關鍵字限定,說明它不可以被繼承,沒有子類。即持有一個String對象的引用,它必然是String類,而不會是其他的類。
- value[]是用來存儲值的,被final關鍵字修飾,說明這個數組不可被其它數組替換—即數組的地址不可變更,但是數組的每個元素的值可以變更
private 限定符,保證String字符串數組的值不可在類外被修改。由於未對外暴露可修改的接口,所以String的值一旦被創建,即不可被修改。
- 線程安全
因為字符串是不可修改的(只能讀不能寫),多個線程可以共享同一個字符串實例
- 字符串常量池可以大大提高時空間效率
字符串常量池,詳情請移步 https://segmentfault.com/a/1190000009888357
2、JDK8的HashMap的源碼,實現原理,底層結構
HashMap的Hash沖突解決,后面單獨會寫一篇博客。
ConcurrentHashMap的鎖分段,大廠很喜歡問(最近華為電話面試問過我),簡單說一句,就是hashMap的數據是一個數組,用多個鎖來鎖,一個鎖鎖一個節點的數據鏈。
不像以前一個鎖鎖住整個數組,多個線程可分段訪問這些數據,自然效率就高了
- 首先看Node的源碼
static class Node<K,V> implements Map.Entry<K,V> {
final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; }
HashMap用 transient Node<K,V>[] table 存值,本質上是鏈表數組(哈希數組+鏈表+紅黑樹),是Hash散列的,即數組非緊密排列,有空隙,詳見下圖
圖01
為什么有紅黑樹,看put(新增)的源碼片段,如下:
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
TreeNode定義的源碼片段,如下:
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // red-black tree links
TreeNode<K,V> left; TreeNode<K,V> right; TreeNode<K,V> prev; // needed to unlink next upon deletion boolean red; TreeNode(int hash, K key, V val, Node<K,V> next) { super(hash, key, val, next); }
- 容量及動態擴容
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
默認容量-16。resize時,newCap = oldCap << 1( 2進制,左移1位,即*2,舊的容量翻倍,容量可能不是2的冪,視就又容量情況而定)
- 新增元素
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true); }
1)如果以前這個key有值,put 操作會用新值替換舊值。
2)Hash沖突怎么解決
hash(散列),就是key和存儲位置有個映射關系f,我們稱之為hash函數。hash沖突,就是不同的key,根據hash函數算出來的存儲位置相同,后面添加的元素就和原來的hashCode沖突了,所以要重新按照一定規則計算新的存儲位置。普通HashMap(java 8的HashMap結構如“圖1”,有紅黑樹)結構如下圖:
java8 中的HashMap為了提高查找效率,當鏈表沖突過高,大於閾值時,會將鏈表節點轉化成紅黑樹節點
- 裝載因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
load factor默認0.75 ,這個和概率統計有關(Hash沖突概率最低),詳見 http://en.wikipedia.org/wiki/Poisson_distribution
為了減少沖突,當hashMap的數組長度 > 臨界值 就會觸發擴容,所有元素rehash(重新計算hashCode和存儲位置)再放到擴容后的容器中,因為涉及到計算、數據查找、內存拷貝、移動等操作,非常耗時。
臨界值 = current capacity * current load factor。默認臨界值 = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR = 16 x 0.75 = 12時,就會觸發擴容操作。
*****************************************************************************************************
精力有限,想法太多,專注做好一件事就行
- 我只是一個程序猿。5年內把代碼寫好,技術博客字字推敲,堅持零拷貝和原創
- 寫博客的意義在於鍛煉邏輯條理性,加深對知識的系統性理解,鍛煉文筆,如果恰好又對別人有點幫助,那真是一件令人開心的事
*****************************************************************************************************