package collections;
import java.util.Collection;
import java.util.Set;
//类的范型参数,文件名称没有 范型参数描述。
//开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列) 再哈希法 链地址法 建立一个公共溢出区
public interface MyMap<K, V> {
boolean isEmpty(); //如果此映射未包含键-值映射关系,则返回 true。
int size() ;//返回此映射中的键-值映射关系数。
V put(K key, V value); //将指定的值与此映射中的指定键关联(可选操作)。
void putAll(MyMap<? extends K,? extends V> m) ;//从指定映射中将所有映射关系复制到此映射中(可选操作)。
boolean containsKey(K key) ; //如果此映射包含指定键的映射关系,则返回 true。
boolean containsValue(V value);//如果此映射将一个或多个键映射到指定值,则返回 true。
//三种集合视图 和单个值对象
V get(K key); //返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
Set<K> keySet(); //返回此映射中包含的键的 Set 视图。
Collection<V> values(); //返回此映射中包含的值的 Collection 视图。
Set<MyMapEntry<K,V>> entrySet() ;//返回此映射中包含的映射关系的 Set 视图。
V remove(K key); //如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。
void clear(); //从此映射中移除所有映射关系(可选操作)。
boolean equals(Object o) ;//比较指定的对象与此映射是否相等。
int hashCode(); //返回此映射的哈希码值。
}
package collections;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
// Map 接口提供三种collection 视图,允许以键集、值集或键-值映射关系集的形式查看某个映射的内容。
//所有通用的映射实现类应该提供两个“标准的”构造方法:一个 void(无参数)构造方法,用于创建空映射;
//一个是带有单个 Map 类型参数的构造方法,用于创建一个与其参数具有相同键-值映射关系的新映射。
//HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。//打个比方, 第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。
//一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B,
//如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。
public class MyHashMap<K,V> implements MyMap<K,V>,Cloneable, Serializable {
private static final long serialVersionUID = 364045005810968434L;
private MyMapEntryImpl[] table;//Entry数组表
static final int DEFAULT_INITIAL_CAPACITY = 16;//默认数组长度
private int size;
// 构造函数
public MyHashMap() {
table = new MyMapEntryImpl[DEFAULT_INITIAL_CAPACITY];
size = DEFAULT_INITIAL_CAPACITY;
}
MyHashMap(int initialCapacity){};//构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
MyHashMap(int initialCapacity, float loadFactor){} //构造一个带指定初始容量和加载因子的空 HashMap。
MyHashMap(MyHashMap<? extends K,? extends V> m){} //构造一个映射关系与指定 Map 相同的新 HashMap。
//获取数组长度
public int getSize() {
return size;
}
// 求index 列表的 哈希索引位置
static int indexFor(int h, int length) {
return h % (length - 1);
}
//获取元素
public V get(K key) {
if (key == null)
return null;
int hash = key.hashCode();// key的哈希值
int index = indexFor(hash, table.length);// 求key在数组中的下标
for (MyMapEntryImpl<K, V> e = table[index]; e != null; e = e.next) {
K k = e.key;
//hashcode 相同 及 equals也相同
if (e.key.hashCode() == hash && (k == key || key.equals(k)))
return e.value;
}
return null;
}
// 添加元素 有的话 返回原来旧的值《
public V put(K key, V value) {
//允许null null 键值对
if (key == null)
return null;
int hash = key.hashCode();
int index = indexFor(hash, table.length);
// 如果添加的key已经存在,那么只需要修改value值即可
for (MyMapEntryImpl<K, V> e = table[index]; e != null; e = e.next) {
K k = e.key;
if (k.hashCode() == hash && (k == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
return oldValue;// 原来的value值
}
}
// 如果key值不存在,那么需要添加
MyMapEntryImpl<K, V> e = table[index];// 获取当前数组中的e
table[index] = new MyMapEntryImpl<K, V>(key, value, e);// 新建一个Entry,并将其指向原先的e
return null;
}
public void clear() {
// TODO Auto-generated method stub
}
public boolean containsKey(Object key) {
// TODO Auto-generated method stub
return false;
}
public boolean containsValue(Object value) {
// TODO Auto-generated method stub
return false;
}
public Set entrySet() {
// TODO Auto-generated method stub
return null;
}
public boolean isEmpty() {
// TODO Auto-generated method stub
return false;
}
public Set keySet() {
// TODO Auto-generated method stub
return null;
}
public void putAll(MyMap m) {
// TODO Auto-generated method stub
}
public V remove(K key) {
// TODO Auto-generated method stub
return null;
}
public int size() {
// TODO Auto-generated method stub
return 0;
}
public Collection values() {
// TODO Auto-generated method stub
return null;
}
}
public interface MyMapEntry<K, V> {
K getKey() ;//返回与此项对应的键。
V getValue(); //返回与此项对应的值。
V setValue(V value);
boolean equals(Object o);//比较指定对象与此项的相等性。
// (e1.getKey()==null ? e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
// (e1.getValue()==null ? e2.getValue()==null : e1.getValue().equals(e2.getValue()))
int hashCode(); //返回此映射项的哈希码值。
// (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
// (e.getValue()==null ? 0 : e.getValue().hashCode())
}
package collections;
/**
* hashMap 因为不能修改 键值 所以定义为 final
* @author wangyuehui
* @param <K>
* @param <V>
*/
public class MyMapEntryImpl<K, V> implements MyMapEntry<K, V> {
final K key;
V value;
MyMapEntryImpl<K,V> next;//下一个结点
//构造函数
public MyMapEntryImpl(K k, V v, MyMapEntryImpl<K,V> n) {
key = k;
value = v;
next = n;
}
public final K getKey() {
return key;
}
public final V getValue() {
return value;
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
@SuppressWarnings("unchecked")
public final boolean equals(Object o) {
//首先判断 是不是当前对象
//编程技巧 instanceof 回车 自动构建代码块
if (!(o instanceof MyMapEntryImpl))
return false;
MyMapEntryImpl<K, V> e = (MyMapEntryImpl<K, V>)o;
//先判断键,再判断值 《自身对象,和 其他对象的比较》
K k1 = getKey();
K k2 = e.getKey();
//这个时候有 null值 及 null键的逻辑判断
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
V v1 = getValue();
V v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}
public final int hashCode() {
//括号加错了,算法的实现逻辑
return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode());
}
public final String toString() {
return getKey() + "=" + getValue();
}
}