HashMap

package com.zhuyu_deng.test;

import java.io.Serializable;


/** 属性: Entry[] table; 数组结构,Entry,结点,可延伸做链表(Entry)内部重新equals(),hashCode(),toString();
 * 		currentSize,当前大小
 * 		modCount,修改次数,HashMap是非同步的,当迭代器运行的时候,有其他的线程修改HashMap的时候,会fast-fail
 * 		threshold,阈值,权衡空间与查找时间,由table的长度length和加载因素LOADFACOR决定的。
 * 		LOAD_FACTOR,加载因素
 * 		表的默认大小,为2的幂(必须),DEFAULT_TABLE_SIZE;
 * 
 * 对外接口:对外接口往往够过调用内部接口完成功能
 * 		构造函数:1.HashMap()     经验:在初始化属性时,最好将多个构造函数最终调用到一个构造函数中,由一个构造函数完成属性初始化。
 * 			  2.HashMap(tableSize) 加载因素一律使用默认的LOAD_FACTOR = 0.75F;
 * 			  3.V put(K key, V value);
 * 			  4.V get(Object key);  // 除了put,其他的关于Key的参数都是Object,会调用到查找,无论是内部还是外部,被调用的函数参数为Object key
 *			  5. void clear();
 *			  6. int size();
 *			  7. boolean isEmpty();
 *			  8. containsKey();
 * 内部接口:
 */
public class MyMap<K, V> implements Serializable
{
//	属性
	private static int DEFAULT_TABLE_SIZE = 16;
	private int currentSize;
	private Entry[] table;
	private int modCount;
	private int threshold;
	private static float LOAD_FACTOR = 0.75F;
	
	private static class Entry<K, V>
	{
		final int hash;
		Entry<K, V> next;
		K key;
		V value;
		
		public Entry(int h, Entry<K, V> e, K k, V v)
		{
			hash = h;
			next = e;
			key = k;
			value = v;
		}
		
		public K getKey()
		{
			return key;
		}
		
		public V getValue()
		{
			return value;
		}
		
		public V setValue(V newValue)
		{
			V oldValue = value;
			value = newValue;
			return oldValue;
		}
		
		public boolean equals(Object o)
		{
			if (!(o instanceof Entry))
				return false;
			Entry e = (Entry) o;
			Object k1 = getKey();
			Object k2 = e.getKey();
//			== or equals(),相等
			if (k1 == k2 || (k1 != null && k1.equals(k2)))
			{
				Object v1 = getValue();
				Object v2 = e.getValue();
				if (v1 == v2 || (v1 != null && v1.equals(v2)))
					return true;
			}
			return false;
		}
		
		public int hashCode()
		{
			return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
		}
		
		public String toString()
		{
			return getKey() + " = " + getValue();
		}
	}
//	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	构造函数
	
//	有多个构造函数,但是让这些构造函数都调用一个构造函数
	public MyMap()
	{
		this(DEFAULT_TABLE_SIZE);
	}
	
	public MyMap(int n)
	{
		int capacity = 1;
		
		while (capacity < n)
			capacity <<= 1;
		table = new Entry[capacity];
		threshold = (int) (capacity * LOAD_FACTOR);
	}
//	/////////////////////////////////////////////////////////////////////////////////
//	清空
	public void clear()
	{
		modCount++;
		Entry[] tab = table;
		for (int i = 0; i < tab.length; ++i)
			tab[i] = null;
		currentSize = 0;
	}
//	返回元素个数
	public int size()
	{
		return currentSize;
		
	}
//	返回容量
	public int capacity()
	{
		return table.length;
	}
//	判空
	public boolean isEmpty()
	{
		return currentSize == 0;
	}
	
//	///////////////////////////////////////////////////////////////////////////////////////////////
//	判断是否有key对应的Entry
	public boolean containsKey(Object key)
	{
		return getEntry(key) != null;
	}
//	返回key对应的Entry<K, V>对应
	private Entry<K, V> getEntry(Object key)
	{
		int hashCode = hash(key.hashCode());
		for (Entry<K, V> e = table[indexFor(hashCode, table.length)]; e != null; e = e.next)
		{
			Object k;
			if (hashCode == e.hash && ((k = e.key) == key || (k != null && k.equals(key))))
				return e;
		}
		return null;
	}
//	///////////////////////////////////////////////////////////////////////////////////////////////////

//	判断是否有value
	public boolean containsValue(Object value)
	{
		if (value == null)
			return containsNullKey();
		Entry[] tab = table;
		for (int i = 0; i < tab.length; ++i)
		{
			for (Entry<K, V> e = table[i]; e != null; e = e.next)
			{
				Object k = e.value;
				if (value.equals(k))
					return true;
			}
		}
		return false;
	}
	
	private boolean containsNullKey()
	{
		Entry[] tab = table;
		for (int i = 0; i < tab.length; ++i)
		{
			for (Entry<K, V> e = table[i]; e != null; e = e.next)
			{
				if (e.value == null)
					return true;
			}
		}
		return false;
	}
//	取出
	public V get(Object key)
	{
		if (key == null)
			return getForNullKey();
		int hashCode = hash(key.hashCode());
		for (Entry<K, V> e = table[indexFor(hashCode, table.length)]; e != null; e = e.next)
		{
			Object k;
			if (e.hash == hashCode && ((k = e.key) == key || k.equals(key)))
			{
				return e.value;
			}
		}
		return null;
	}
	private V getForNullKey()
	{
		for (Entry<K, V> e = table[0]; e != null; e = e.next)
		{
			if (e.key == null)
				return e.value;
		}
		return null;
	}
//	添加
	public V put(K key, V value)
	{
		if (key == null)
			return putForNullKey(value);
		int hashCode = hash(key.hashCode());
		int i = indexFor(hashCode, table.length);
		
		for (Entry<K, V> e = table[i]; e != null; e = e.next)
		{
			Object k;
			if (hashCode == e.hash && ((k = e.key) == key || e.equals(key)))
			{
				V oldValue = e.value;
				e.value = value;
				return oldValue;
			}
		}
		modCount++;
		addEntry(hashCode, i, key, value);
		return null;
	}
//	
	private V putForNullKey(V value)
	{
		for (Entry<K, V> e = table[0]; e != null; e = e.next)
		{
			if (e.key == null)
			{
				V oldValue = e.value;
				e.value = value;
				return oldValue;
			}
		}
		modCount++;
		addEntry(0, 0, null, value);
		return null;
	}
	public V remove(Object key)
	{
		Entry<K, V> e = removeEntryForKey(key);
		return (e == null ? null : e.value);
	}
	private Entry<K, V> removeEntryForKey(Object key)
	{
		int hashCode = hash(key.hashCode());
		for (Entry<K, V> e = table[indexFor(hashCode, table.length)]; e != null; e = e.next)
		{
			Object k;
			if (hashCode == e.hash && (    (k = e.key) == key || (k != null && k.equals(key))   ))
			{
				modCount++;
				currentSize--;
				
				Entry<K, V> currentEntry = e;
				e = e.next;
				return currentEntry;
			}
		}
		return null;
	}
//	addEntry
	private void addEntry(int hashCode, int index, K key, V value)
	{
		Entry<K, V> e = table[index];  // 表table[index]被e接过来
		table[index] = new Entry<K, V>(hashCode, e, key, value);  // table[index]接个newEntry,然后在接e;
		
		if(currentSize++ > threshold)
			resize(table.length * 2);
		
	}
	
	private void resize(int newCapacity)
	{
		Entry[] newTable = new Entry[newCapacity];
		transfer(newTable);
		table = newTable;
		threshold = (int)(LOAD_FACTOR * newCapacity);
	}
	private void transfer(Entry[] newTable)
	{
		Entry[] src = table;
		int oldCapacity = src.length;
		for (int i = 0; i < src.length; ++i)
		{
			Entry<K, V> e = src[i];  // e把第i个链接过来
			if (e != null)
			{
				src[i] = null;
				do
				{
					Entry<K, V> next = e.next;
					int index = indexFor(e.hash, newTable.length);
					e.next = newTable[index];
					newTable[index] = e;
					e = next;
				}while(e != null);
			}
		}
	}
//	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 获取hashCode
	private int hash(int h)
	{
		h ^= (h >>> 20) ^ (h >>> 12);
		return h ^ (h >>> 7) ^ (h >>> 4);
	}
//	确定在table中的位置
	private int indexFor(int h, int length)
	{
		return h & (length - 1);
	}
}


05-23
### JavaHashMap 的使用方法 #### 1. **简介** `HashMap` 是 Java 集合框架中的一个重要类,用于存储键值对(key-value pair)。它的底层基于哈希表实现,提供了快速的查找、插入和删除操作。`HashMap` 不保证元素的顺序,并允许一个 `null` 键和多个 `null` 值。 #### 2. **基本操作** 以下是 `HashMap` 的一些常用方法及其功能: - **put(key, value)**: 将指定的键值对存入 `HashMap`。 - **get(key)**: 返回与指定键关联的值。 - **remove(key)**: 移除指定键对应的映射关系。 - **size()**: 返回 `HashMap` 中键值对的数量。 - **clone()**: 创建并返回该 `HashMap` 对象的一个副本。 - **isEmpty()**: 如果此 `HashMap` 映射不包含任何键值对,则返回 true。 这些方法的具体用法可以通过下面的例子来说明。 --- #### 3. **示例代码** ##### 示例 1: 添加键值对并获取大小 ```java // Java program to demonstrate the use of size() method in HashMap import java.util.*; public class SizeExample { public static void main(String[] args) { // Create an empty HashMap Map<Integer, String> map = new HashMap<>(); // Add key-value pairs using put() map.put(10, "C"); map.put(20, "C++"); map.put(50, "JAVA"); map.put(40, "PHP"); map.put(30, "SFDC"); // Print the HashMap content System.out.println("HashMap Content: " + map); // Get the number of entries in the HashMap int size = map.size(); System.out.println("Size of HashMap: " + size); } } ``` 这段代码展示了如何向 `HashMap` 插入数据以及计算其大小[^1]。 --- ##### 示例 2: 删除特定键值对 ```java // Java program to demonstrate the removal operation in HashMap import java.util.*; public class RemoveExample { public static void main(String[] args) { // Initialize a HashMap with some data Map<Integer, String> map = new HashMap<>(); map.put(10, "C"); map.put(20, "C++"); map.put(50, "JAVA"); map.put(40, "PHP"); map.put(30, "SFDC"); // Display initial state System.out.println("Initial HashMap: " + map); // Remove entry associated with key '50' map.remove(50); // Show updated HashMap after deletion System.out.println("Updated HashMap after removing key '50': " + map); } } ``` 这里演示了如何移除某个键所对应的数据项[^2]。 --- ##### 示例 3: 复制一份新的 HashMap 实例 ```java // Example demonstrating cloning functionality within HashMaps. import java.util.*; public class CloneExample { public static void main(String[] args) { // Original HashMap creation and population HashMap<Integer, String> originalMap = new HashMap<>(); originalMap.put(10, "C"); originalMap.put(20, "C++"); originalMap.put(50, "JAVA"); originalMap.put(40, "PHP"); originalMap.put(30, "SFDC"); // Cloning process begins here HashMap<Integer, String> clonedMap = (HashMap<Integer, String>)originalMap.clone(); // Output both maps post-cloning action System.out.println("Original HashMap Contents: " + originalMap); System.out.println("Cloned HashMap Contents: " + clonedMap); } } ``` 本部分解释了复制现有 `HashMap` 的过程[^3]。 --- #### 4. **性能特点与其他注意事项** 由于 `HashSet` 内部依赖于 `HashMap` 来管理其成员集合,因此它们共享相似的时间复杂度特性——平均情况下 O(1),最坏情况取决于冲突处理机制[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值