1. 程式人生 > >原始碼分析之手寫1.7HahMap(三)

原始碼分析之手寫1.7HahMap(三)

public interface ExtMap<K, V> {

	// 向集合中插入資料
	public V put(K k, V v);

	// 根據k 從Map集合中查詢元素
	public V get(K k);

	// 獲取集合元素個數
	public int size();

	interface Entry<K, V> {
		K getKey();

		V getValue();

		V setValue(V value);
	}

 

 


import com.mayikt.jdk7hash.ExtMap.Entry;

/**
 * 手寫jdk1.7的hashMap
 * 
 * @author zjmiec
 *
 */
public class ExtJdk7HaspMap<K, V> implements ExtMap<K, V> {

	// 1.定義table 存放HashMap 陣列元素 預設不初始化容器 攔截在
	Node<K, V>[] table = null;
	// 2.實際用到table 儲存容量大小
	int size;
	/**
	 * 3.預設負載因子 0.75 擴容用到,負載因子越小。hash衝突機率越低, 根據每個連結串列個數
	 */
	float DEFAULT_LOAD_FACTOR = 0.75f;
	// 4.table 預設初始大小 16
	int DEFAULT_INITIAL_CAPACITY = 16;

	public V put(K k, V v) {
		// 1.判斷table陣列大小是否為空(如果為空,做初始化操作)
		if (table == null) {
			table = new Node[DEFAULT_INITIAL_CAPACITY];
		}
		/**
		 * 2.判斷陣列 是否需要擴容 為什麼需要擴容? 使用連結串列查詢,連結串列越長,查詢效率越慢,而且, 陣列儲存採用hash下標,
		 * 過短會導致hash衝突的機率增加 如果size大於12,進行擴容陣列,大小為之前的兩倍
		 */
		if (size > DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY) {
			// 開始對陣列擴容

		}
		// 3.計算hash制定下標
		int index = getIndex(k, DEFAULT_INITIAL_CAPACITY);
		Node<K, V> node = table[index];
		if (node == null) {
			// 沒有hash衝突
			node = new Node<K, V>(k, v, null);
			size++;
			// return node.setValue(v);
		} else {
			Node<K, V> newNode = node;
			// 發生hash衝突key 直接新增(衝突node)到前面了,不是往後加
			while (newNode != null) {
				if (newNode.getKey().equals(k) || newNode.getKey() == k) {
					// hash相同,而且equals相同 說明是同一個物件,進行修改值
					// node.value=v;
					return newNode.setValue(v);
				} else {
					// 繼續新增 排在前面hashCode 取模餘數相同存
					if (newNode.next == null) {
						// 遍歷node到最後沒有存在相同的key,就會新增node
						node = new Node<K, V>(k, v, node);
						size++;
					}
				}
				newNode = newNode.next;
			}

		}
		table[index] = node;
		return null;
	}

	private void resize() {
		// 1.生成新的table,長度為之前的兩倍
		Node<K, V>[] newTable = new Node[DEFAULT_INITIAL_CAPACITY << 1];
		// 2.重新計算index的索引,存放到新的table容器
		for (int i = 0; i < table.length; i++) {
			Node<K, V> oldNode = table[i];
			while (oldNode != null) {
				table[i] = null;// 垃圾回收
				// 獲取之前的key
				K oldkey = oldNode.key;
				// 重新計算index
				int index = getIndex(oldkey, newTable.length);
				// 存放在之前的table 原來的node next
				ExtJdk7HaspMap<K, V>.Node<K, V> next = oldNode.next;
				// 如果index在newTablez發生衝突,以連結串列方式儲存
				// 原來連結串列存放的是A,B,C,新連結串列會儲存為C,B,A
				// 原來node存放新node的下一個節點
				oldNode.next = newTable[index];
				// 將之前的node賦值給newTable[index]
				newTable[index] = oldNode;
				//
				oldNode = next;
			}
		}
		// 3.將新的table的賦值給舊的table
		table = newTable;
		DEFAULT_INITIAL_CAPACITY = newTable.length;
		newTable = null;
	}

	void print() {
		System.out.println("-------" + table.length);
		for (int i = 0; i < table.length; i++) {
			Node<K, V> node = table[i];
			System.out.print("下標位置:" + i);
			while (node != null) {
				System.out.print("[ key:" + node.getKey() + ",value:" + node.getValue() + "]");
				node = node.next;

				/*
				 * if(node.next!=null){ node=node.next; }else{ node=null; }
				 */
			}
			System.out.println();
		}
	}

	public V get(K k) {
		int index = getIndex(k, DEFAULT_INITIAL_CAPACITY);
		Node<K, V> node = getNode(table[getIndex(k, DEFAULT_INITIAL_CAPACITY)], k);
		return node == null ? null : node.value;
	}

	public Node<K, V> getNode(Node<K, V> node, K k) {
		while (node.next != null) {
			if (node.getKey().equals(k)) {
				return node;
			}
			node = node.next;
		}
		return null;
	}

	public int size() {
		// TODO Auto-generated method stub
		return 0;
	}

	public int getIndex(K k, int length) {
		int hashCode = k.hashCode();
		int hash = hashCode % table.length;
		return hash;
	}

	class Node<K, V> implements Entry<K, V> {

		// 存放Map 集合key
		private K key;
		// 存放map 集合value
		private V value;

		private Node<K, V> next;

		public K getKey() {

			return this.key;
		}

		public Node(K key, V value, Node<K, V> next) {
			super();
			this.key = key;
			this.value = value;
			this.next = next;
		}

		public V getValue() {
			// TODO Auto-generated method stub
			return this.value;
		}

		public V setValue(V value) {
			// 設定新值 返回老值
			V oldValue = this.value;
			this.value = value;
			return oldValue;
		}

	}

}