public class MyHashMap<K, V> { private class Entry<K, V> { int hash; K key; V value; Entry<K, V> next; Entry(int hash, K key, V value, Entry<K, V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } } private static final int DEFAULT_CAPACITY = 1 << 2; private Entry<K, V>[] table; private int capacity; private int size; private final float loadFactor = 0.75f; public MyHashMap() { this(DEFAULT_CAPACITY); } @SuppressWarnings("unchecked") public MyHashMap(int capacity) { if (capacity < 0) { throw new IllegalArgumentException(); } else { table = new Entry[capacity]; size = 0; this.capacity = capacity; } } public int size() { return size; } public boolean isEmpty() { return size == 0 ? true : false; } public V put(K key, V value) { if (key == null) { throw new RuntimeException("key cannot be empty!"); } if (size >= capacity * loadFactor) { // start rehash resize(2 * table.length); int hash = (null != key) ? hash(key) : 0; int index = indexFor(hash, table.length);// Note that the table has been expanded at this time } V newValue = putEntry(key, value); return newValue; } @SuppressWarnings({ "rawtypes", "unchecked" }) private void resize(int newCapacity) { System.out.println("We are going to expand!! The current size is: " + size); // multiply the length of the array by twice Entry[] newTable = new Entry[newCapacity]; transfer(newTable, true); table = newTable; } @SuppressWarnings({ "rawtypes", "unchecked" }) private void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K, V> e : table) { while (e != null) { if (rehash) { // to re-hash e.hash = null == e.key ? 0 : hash(e.key); } int index = indexFor(e.hash, newCapacity); // start putting e into the new array // Note that every time a new value is inserted, it must be inserted at the head of the hash list e.next = newTable[index]; newTable[index] = e; e = e.next; } } } private V putEntry(K key, V value) { if (key == null) { throw new RuntimeException("key cannot be empty!"); } int hash = hash(key); int i = indexFor(hash, table.length); Entry<K, V> newEn = new Entry<K, V>(hash, key, value, null); for (Entry<K, V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { // Represents that the current e conflicts with the key to be added, then overwrite V oldValue = e.value; e.value = value;// The current value of e should be replaced with the new value return oldValue; } } // If the above is not found, it is necessary to add an element to the linked list size++; addEntry(newEn, i); return value; } private void addEntry(Entry<K, V> entry, int index) { Entry<K, V> e = table[index]; table[index] = entry; entry.next = e; } public V get(K key) { if (key == null) { throw new RuntimeException("key cannot be empty!"); } Entry<K, V> entry = getEntry(key); return null == entry ? null : entry.value; } private Entry<K, V> getEntry(K key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key); int i = indexFor(hash, table.length); for (Entry<K, V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { return e; } } return null; } public V remove(K key) { Entry<K, V> e = removeEntryForKey(key); return (e == null ? null : e.value); } private Entry<K, V> removeEntryForKey(K key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key); int i = indexFor(hash, table.length); Entry<K, V> cur = table[i]; Entry<K, V> e = cur; while (e != null) { if (e.hash == hash && (e.key == key || key.equals(e.key))) { size--; // if the delete is prev if (cur == e) { table[i] = e.next; } else { // Let cur's next equal to e's next cur.next = e.next; } return e; } cur = e; e = e.next; } return null; } private int indexFor(int hash, int length) { return hash & (length - 1);// The hash value and the length minus one do the AND operation } private int hash(K key) { return key.hashCode(); } public static void main(String[] args) { MyHashMap<Integer, String> map = new MyHashMap<>(); } }