手动实现java常用的容器-hashmap
(方法只是模拟java源码,效率没有底层源码高,纯属学习熟悉底层源码)
节点结构图
容器结构图
节点源码
package com.alan.alanhashmap;
/**
* author Mr.ALan
* DESCRIPTION 一个自定义的hashmap节点对象
* create 2019/4/11
*/
public class Node<K, V> {
// 确定在位桶数组的位置,通过hashcode计算得来
int hash;
// 用于存放数据的键
private K key;
// 用于存放数据的值
private V value;
// 用于指向下一个节点
private Node next;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
public Node(int hash, K key, V value) {
this.hash = hash;
this.key = key;
this.value = value;
}
public Node() {
}
public int getHash() {
return hash;
}
public void setHash(int hash) {
this.hash = hash;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
容器源码
package com.alan.alanhashmap;
import java.util.ArrayList;
import java.util.HashSet;
/**
* author Mr.ALan
* DESCRIPTION
* create 2019/4/11
*/
@SuppressWarnings("all")
public class AlanHashMap<K, V> {
// 位桶数组用于散列存放键值对对象
Node[] table;
// 默认的位桶数组容量
public static final int DEFAULT_SIZE = 16;
// 记录有效的键值对个数
private int size;
public AlanHashMap() {
table = new Node[DEFAULT_SIZE];
}
// 用于创建指定大小的位桶数组
public AlanHashMap(int size) {
table = new Node[size];
}
// 添加一个元素 重复时更新数据
public void put(K key, V value) {
Node newNode = new Node(key, value);
int index = gethash(newNode);
if (table[index] == null) {
table[index] = newNode;
newNode.setHash(index);
size++;
} else {
Node tempNode = table[index];
do {
if (tempNode.getKey().equals(newNode.getKey())) {
tempNode.setValue(newNode.getValue());
return;
} else {
if (tempNode.getNext() == null) {
tempNode.setNext(newNode);
size++;
return;
}
tempNode = tempNode.getNext();
}
} while (tempNode.getNext() != null);
}
}
// 删除一个元素
public void remove(K key) {
Node tempNode;
Node tempNodeLast;
for (int i = 0; i < table.length; i++) {
tempNodeLast = table[i];
tempNode = table[i];
while (tempNode != null) {
if (table[i].getKey().equals(key)) {
table[i] = table[i].getNext();
size--;
return;
}
if (tempNode.getKey().equals(key)) {
tempNodeLast.setNext(tempNode.getNext());
size--;
return;
}
tempNode = tempNode.getNext();
if (tempNodeLast.getNext() != tempNode) {
tempNodeLast = tempNodeLast.getNext();
}
}
}
}
// 清空容器
public void clear() {
table = null;
size = 0;
}
// 通过键获取一个值
public V get(K key) {
HashSet<Node> set = entrySet();
for (Node node : set) {
if (node.getKey().equals(key)) {
return (V) node.getValue();
}
}
return null;
}
// 获取所有的键值对对象
public HashSet<Node> entrySet() {
HashSet<Node> set = new HashSet<>();
Node tempNode;
for (Node node : table) {
tempNode = node;
while (tempNode != null) {
set.add(tempNode);
tempNode = tempNode.getNext();
}
}
return set;
}
// 获取所有的键对象 不可以有重复的值
public HashSet<K> keySet() {
HashSet<K> keySet = new HashSet<>();
for (Node node : entrySet()) {
keySet.add((K) node.getKey());
}
return keySet;
}
// 获取所有的值对象 可以有重复的值
public ArrayList<V> values() {
ArrayList<V> values = new ArrayList<>();
for (Node node : entrySet()) {
values.add((V) node.getValue());
}
return values;
}
// 返回有效的键值对对数
public int size() {
return size;
}
// 判断是否为空
public boolean isEmpty() {
return size == 0;
}
// 利用节点的key和位桶数组的长度来计算节点的hash值(hash值不是hashcode值,而是由hashcode计算后得来)
public int gethash(Node node) {
return node.getKey().hashCode() % table.length;
}
// 判断是否包含某个键
public boolean contains(K key) {
HashSet<K> ks = keySet();
for (K k : ks) {
if (k.equals(key)) {
return true;
}
}
return false;
}
// 打印集合的内容
@Override
public String toString() {
HashSet<Node> set = entrySet();
StringBuilder sb = new StringBuilder("{");
if (set.size() == 0) {
return sb.append('}').toString();
}
for (Node node : set) {
sb.append('[').append(node.getKey()).append(':')
.append(node.getValue()).append(']').append((char) 32);
}
sb.setCharAt(sb.length() - 1, '}');
return sb.toString();
}
}
ps:纯属学习交流,若有错误欢迎纠错