public class YcHashMap<K, V> {
protected Node[] nodes; // 数组 + 链表
protected int size; // 用来记录元素个数
public YcHashMap() {
this(16);
}
@SuppressWarnings("unchecked")
public YcHashMap(int capacity) {
nodes = new YcHashMap.Node[capacity];
}
/**
* 如果数组长度为16,那么映射出来的索引下标值为[0, 15]
* 也就是说hashCode跟length进过某种运算后,得到的值的范围为[0, 15] hashCode % 16;
* 0000 1111
* 根据hashCode和数组长度获取这个键在数组中的索引下标
* @param hashCode 键的hash值
* @param length 数组长度
* @return
*/
public static int getIndex(int hashCode, int length) {
return hashCode & (length - 1);
}
/**
* 添加元素的方法
* @param key
* @param value
*/
public void put(K key, V value) {
// 创建一个新的节点
Node newNode = new Node();
// 获取这个节点要存放的索引下标
int index = getIndex(key.hashCode(), nodes.length);
// 构建节点信息
newNode.key = key;
newNode.value = value;
newNode.next = null;
// 判断这个索引位置有没有对象
Node node = nodes[index];
if (node == null) { // 说明这个位置没有对象
nodes[index] = newNode;
++ size;
return;
}
// 如果这个地方有对象,那么要将这个新节点,链接到这个列表的最后面
Node lastNode = null; // 用来存放最后一个节点
while (node != null) { // 说明不是最后一个节点
if (node.key.equals(key)) { // 判断当前节点的键是否跟要添加的键相同,如果相同,则覆盖,不添加
node.value = value;
return;
}
lastNode = node;
node = node.next;
}
// 说明键没有重复,那么要追加
lastNode.next = newNode;
++ size;
}
/**
* 根据键获取元素的方法
* @param key
* @return
*/
public V get(K key) {
// 根据键获取这个对象存放的列表
int index = getIndex(key.hashCode(), nodes.length);
Node node = nodes[index];
if (node == null) { // 说明没有该对象
return null;
}
V value = null;
while (node != null) {
if (node.key.equals(key)) { // 如果当前节点存到的键跟我要找的键相同,则说明这个对象找到了,返回
return node.value;
}
// 获取下一个节点
node = node.next;
}
return value;
}
/**
* 根据键移除对象
* @param key
*/
public void remove(K key) {
// 根据键获取这个对象存放的列表
int index = getIndex(key.hashCode(), nodes.length);
Node node = nodes[index];
if (node == null) { // 说明没有该对象
return;
}
// 当前节点是我要找的节点吗
if (node.key.equals(key)) { // 说明当前节点是我要找的
if (node.hasNext()) { // 如果有下一个节点,则上移
nodes[index] = node.next;
node = null;
return;
}
nodes[index] = null; // 如果这个地方就一个节点,则直接赋空
return;
}
// 如果到这里来了,说明要移除的节点不是第一个节点
while (node.hasNext()) { // 如果有下一个节点
if (node.next.key.equals(key)) { // 下一个节点的键跟我要移除的键相等吗?
if (node.next.hasNext()) {
node.next = node.next.next;
return;
}
node.next = null;
return;
}
node = node.next;
}
}
/**
* 获取所有的键
* @return
*/
public Set<K> keySet() {
Set<K> set = new HashSet<K>();
Node node = null;
for (int i = 0, len = nodes.length; i < len; ++ i) {
node = nodes[i];
while (node != null) {
set.add(node.key);
node = node.next;
}
}
return set;
}
/**
* 获取元素的个数
* @return
*/
public int size() {
return size;
}
/**
* 输出所有内容的方法
*/
public String toString() {
StringBuffer sbf = new StringBuffer();
sbf.append("{");
Node node = null;
for (int i = 0, len = nodes.length; i < len; ++ i) {
node = nodes[i];
while (node != null) {
sbf.append(node.key + " : " + node.value + ", ");
node = node.next;
}
}
sbf.setCharAt(sbf.length() - 2, '}');
return sbf.toString().trim();
}
// 节点内部类
class Node {
protected K key; // 键
protected V value; // 值
protected Node next; // 下一个节点
// 是否有下一个子节点
public boolean hasNext() {
if (this.next != null) {
return true;
}
return false;
}
}
}