关于java中的HashMap实现

关于java中的HashMap实现,java,collections,hashmap,Java,Collections,Hashmap,我试图对hashmap进行研究,并得出以下分析: Q1你们能给我一个简单的映射吗?在这里你们可以展示这个过程。这个过程是如何使用这个公式详细计算给定键的hashcode。计算位置hash%(arraylelength-1))元素应该放在哪里(bucket number),假设我有这个hashMap HashMap map=new HashMap();//HashMap key random order. map.put("Amit","Java"); map

我试图对hashmap进行研究,并得出以下分析:

Q1你们能给我一个简单的映射吗?在这里你们可以展示这个过程。这个过程是如何使用这个公式详细计算给定键的hashcode。计算位置hash%(arraylelength-1))元素应该放在哪里(bucket number),假设我有这个hashMap

HashMap map=new HashMap();//HashMap key random order.
         map.put("Amit","Java");
         map.put("Saral","J2EE");
Q2有时可能发生两个不同对象的哈希代码相同的情况。在这种情况下,2个对象将保存在一个bucket中,并显示为LinkedList。入口点是最近添加的对象。此对象引用另一个对象,其中包含下一个字段和一个字段。最后一个条目引用null。你们能给我看一个真实的例子吗

由于钻头抖动,“Amit”将分配到第10个铲斗。如果没有比特抖动,它将进入第7个桶,因为2044535&15=7。如何做到这一点请详细解释整个计算过程

快照已更新

另一个图像是

Q1:查看
hashCode()
字符串对象的方法实现

问题2:创建一个简单的类,并将其
hashCode()
方法实现为
return1
。这意味着每个对象和该类将具有相同的hashCode,因此将保存在HashMap中的同一个bucket中

如何使用 这个公式

String
的情况下,这是通过
String#hashCode()计算的其实现方式如下:

 public int hashCode() {
    int h = hash;
        int len = count;
    if (h == 0 && len > 0) {
        int off = offset;
        char val[] = value;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }
在这个实现中需要注意的一件有趣的事情是
String
实际上缓存了它的哈希代码。它可以做到这一点,因为
String
是不可变的

如果我计算
字符串
“Amit”的hashcode,它将生成以下整数:

System.out.println("Amit".hashCode());
>     2044535
让我们完成一个简单的地图放置,但是首先我们必须确定地图是如何构建的。 Java
HashMap
最有趣的事实是它总是有2^n个bucket。因此,如果您调用它,默认的存储桶数是16,这显然是2^4

在此映射上执行put操作,它将首先获取密钥的哈希代码。在这个哈希代码上会发生一些奇特的位抖动,以确保糟糕的哈希函数(尤其是那些在低位没有差异的函数)不会“重载”单个bucket

实际负责将密钥分发到存储桶的真正功能如下:

 h & (length-1); // length is the current number of buckets, h the hashcode of the key
这只适用于两个存储桶大小的幂,因为它使用&将密钥映射到存储桶,而不是模

由于钻头抖动,“Amit”将分配到第10个铲斗。如果没有比特抖动,它将进入第7个桶,因为
2044535&15=7

现在我们有了它的索引,我们就可以找到桶了。如果bucket包含元素,我们必须对它们进行迭代,并在找到元素时替换一个相等的条目。 如果在链表中找不到任何项目,我们只会将其添加到链表的开头

HashMap
中的下一个重要内容是调整大小,因此,如果映射的实际大小超过阈值(由当前存储桶数和加载因子决定,在我们的示例中为16*0.75=12),它将调整备份数组的大小。 Resize始终是当前存储桶数的2倍,保证为2的幂,以不破坏查找存储桶的函数

由于存储桶的数量发生变化,我们必须重新刷新表中的所有当前条目。
这是非常昂贵的,因此如果您知道有多少项,您应该使用该计数初始化
哈希映射
,这样它就不必调整整个时间的大小。

了解哈希代码有两个基本要求:

  • 当为给定对象重新计算哈希代码时(该对象没有以改变其标识的方式进行内部更改),它必须生成与上一次计算相同的值。类似地,两个“相同”的对象必须生成相同的哈希代码
  • 当为两个不同的对象计算哈希代码时(从其内部内容的角度来看,这两个对象并不“相同”),两个哈希代码很可能不同
  • 这些目标是如何实现的,是从事这类工作的数学迷们非常感兴趣的主题,但了解细节对于理解哈希表的工作方式并不重要。

    import java.util.Arrays;
    
    import java.util.Arrays;
    public class Test2 {
    public static void main(String[] args) {
        Map<Integer, String> map = new Map<Integer, String>();
        map.put(1, "A");
        map.put(2, "B");
        map.put(3, "C");
        map.put(4, "D");
        map.put(5, "E");
    
        System.out.println("Iterate");
        for (int i = 0; i < map.size(); i++) {
    
            System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
        }
    
        System.out.println("Get-> 3");
        System.out.println(map.get(3));
    
        System.out.println("Delete-> 3");
        map.delete(3);
    
        System.out.println("Iterate again");
        for (int i = 0; i < map.size(); i++) {
    
            System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue());
        }
    }
    
    }
    
    class Map<K, V> {
    
    private int size;
    private Entry<K, V>[] entries = new Entry[16];
    
    public void put(K key, V value) {
    
        boolean flag = true;
        for (int i = 0; i < size; i++) {
    
            if (entries[i].getKey().equals(key)) {
                entries[i].setValue(value);
                flag = false;
                break;
            }
        }
    
        if (flag) {
            this.ensureCapacity();
            entries[size++] = new Entry<K, V>(key, value);
        }
    }
    
    public V get(K key) {
    
        V value = null;
    
        for (int i = 0; i < size; i++) {
    
            if (entries[i].getKey().equals(key)) {
                value = entries[i].getValue();
                break;
            }
        }
        return value;
    }
    
    public boolean delete(K key) {
        boolean flag = false;
        Entry<K, V>[] entry = new Entry[size];
        int j = 0;
        int total = size;
        for (int i = 0; i < total; i++) {
    
            if (!entries[i].getKey().equals(key)) {
                entry[j++] = entries[i];
            } else {
                flag = true;
                size--;
            }
        }
    
        entries = flag ? entry : entries;
        return flag;
    }
    
    public int size() {
        return size;
    }
    
    public Entry<K, V>[] values() {
        return entries;
    }
    
    private void ensureCapacity() {
    
        if (size == entries.length) {
            entries = Arrays.copyOf(entries, size * 2);
        }
    }
    
    @SuppressWarnings("hiding")
    public class Entry<K, V> {
    
        private K key;
        private V value;
    
        public K getKey() {
            return key;
        }
    
        public V getValue() {
            return value;
        }
    
        public void setValue(V value) {
            this.value = value;
        }
    
        public Entry(K key, V value) {
            super();
            this.key = key;
            this.value = value;
        }
    
    }
    }
    
    公共类Test2{ 公共静态void main(字符串[]args){ Map Map=newmap(); 地图.付诸表决(1,“A”); 图.put(2,“B”); 图.put(3,“C”); 图.put(4,“D”); 地图.put(5,“E”); System.out.println(“迭代”); 对于(int i=0;i3”); System.out.println(map.get(3)); System.out.println(“删除->3”); 删除(3); System.out.println(“再次迭代”); 对于(int i=0;iimport java.util.Arrays; public class Test2 { public static void main(String[] args) { Map<Integer, String> map = new Map<Integer, String>(); map.put(1, "A"); map.put(2, "B"); map.put(3, "C"); map.put(4, "D"); map.put(5, "E"); System.out.println("Iterate"); for (int i = 0; i < map.size(); i++) { System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue()); } System.out.println("Get-> 3"); System.out.println(map.get(3)); System.out.println("Delete-> 3"); map.delete(3); System.out.println("Iterate again"); for (int i = 0; i < map.size(); i++) { System.out.println(map.values()[i].getKey() + " : " + map.values()[i].getValue()); } } } class Map<K, V> { private int size; private Entry<K, V>[] entries = new Entry[16]; public void put(K key, V value) { boolean flag = true; for (int i = 0; i < size; i++) { if (entries[i].getKey().equals(key)) { entries[i].setValue(value); flag = false; break; } } if (flag) { this.ensureCapacity(); entries[size++] = new Entry<K, V>(key, value); } } public V get(K key) { V value = null; for (int i = 0; i < size; i++) { if (entries[i].getKey().equals(key)) { value = entries[i].getValue(); break; } } return value; } public boolean delete(K key) { boolean flag = false; Entry<K, V>[] entry = new Entry[size]; int j = 0; int total = size; for (int i = 0; i < total; i++) { if (!entries[i].getKey().equals(key)) { entry[j++] = entries[i]; } else { flag = true; size--; } } entries = flag ? entry : entries; return flag; } public int size() { return size; } public Entry<K, V>[] values() { return entries; } private void ensureCapacity() { if (size == entries.length) { entries = Arrays.copyOf(entries, size * 2); } } @SuppressWarnings("hiding") public class Entry<K, V> { private K key; private V value; public K getKey() { return key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } public Entry(K key, V value) { super(); this.key = key; this.value = value; } } }