java.util.HashMap和HashSet的内部实现

java.util.HashMap和HashSet的内部实现,java,hashmap,hashcode,hashset,language-implementation,Java,Hashmap,Hashcode,Hashset,Language Implementation,我一直在试图理解java.util.HashMap和java.util.HashSet的内部实现 以下是我脑海中闪现的疑惑: 在HashMap/HashSet中,@Override public int hashcode()的重要性是什么?该哈希代码在何处内部使用 我通常看到HashMap的键是一个字符串像myMap。我是否可以将值映射到someObject(而不是字符串),如myMap?我需要遵守哪些合同才能成功实现这一点 提前谢谢 编辑: 我们是说密钥(check!)的散列码是散列表中映射值

我一直在试图理解
java.util.HashMap
java.util.HashSet
的内部实现

以下是我脑海中闪现的疑惑:

  • 在HashMap/HashSet中,
    @Override public int hashcode()
    的重要性是什么?该哈希代码在何处内部使用
  • 我通常看到HashMap的键是一个
    字符串
    myMap
    。我是否可以将值映射到
    someObject
    (而不是字符串),如
    myMap
    ?我需要遵守哪些合同才能成功实现这一点
  • 提前谢谢

    编辑:

  • 我们是说密钥(check!)的散列码是散列表中映射值的实际对象吗?当我们做
    myMap.get(someKey)时
    java正在内部调用
    someKey.hashCode()
    ,以获取哈希表中要查找结果值的数字
  • 回答:

    编辑2:

  • java.util.HashSet
    中,从何处生成哈希表的键?是我们正在添加的对象,例如mySet.add(myObject)然后
    myObject.hashCode()
    将决定此文件在哈希表中的位置?(因为我们不在哈希集中给出键)
  • 回答:添加的对象成为关键。这个值是哑的

    HashMap/HashSet中@Override public int hashcode()的重要性是什么

    这允许映射实例根据映射的内容生成有用的哈希代码。具有相同内容的两个映射将生成相同的哈希代码。如果内容不同,哈希代码也会不同

    该哈希代码在何处内部使用

    从来没有。此代码的存在只是为了让您可以将一个映射用作另一个映射中的键

    我是否可以将值映射到
    someObject
    (而不是
    String
    )例如
    myMap

    是,但
    someObject
    必须是类,而不是对象(您的名称表明您要传入对象;它应该是
    someObject
    ,以明确您指的是类型)

    我需要遵守哪些合同才能成功实现这一点

    类必须实现
    hashCode()
    equals()

    [编辑]

    我们是说密钥(check!)的散列码是散列表中映射值的实际对象吗


    是的。

    在Java中,equals()、
    hashcode()
    和哈希表(以及.NET)之间存在着复杂的关系。引用文件:

    public int hashCode()

    返回对象的哈希代码值。支持此方法是为了使哈希表受益,例如
    java.util.Hashtable
    提供的哈希表

    hashCode的总合同为:

    • 在Java应用程序的执行过程中,每当在同一对象上多次调用hashCode方法时,只要没有修改对象上的equals比较中使用的信息,hashCode方法必须始终返回相同的整数。从应用程序的一次执行到同一应用程序的另一次执行,该整数不必保持一致
    • 如果根据equals(Object)方法两个对象相等,那么对两个对象中的每一个调用hashCode方法必须产生相同的整数结果
    • 如果根据equals(
      java.lang.Object
      )方法,两个对象是不等的,那么对这两个对象中的每一个调用
      hashCode
      方法都必须产生不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同的整数结果可能会提高哈希表的性能
    只要合理可行,类
    Object
    定义的
    hashCode
    方法会为不同的对象返回不同的整数。(这通常是通过将对象的内部地址转换为整数来实现的,但Java不需要这种实现技术™ 编程语言。)

    线路

    @Overrides public int hashCode()
    

    只告诉您,
    hashCode()
    方法被覆盖。这通常表示在
    HashMap
    中使用类型作为键是安全的

    是的,您可以轻松地使用符合
    HashMap
    equals()
    hashCode()
    契约的任何对象作为键

  • Java中的任何
    对象
    都必须有
    hashCode()
    方法
    HashMap
    HashSet
    都不是异常。如果将哈希映射/集插入另一个哈希映射/集,则使用此哈希代码
  • 任何类类型都可以用作
    HashMap
    /
    HashSet
    中的键。这要求
    hashCode()
    方法为相等的对象返回相等的值,并且
    equals()
    方法根据契约(自反、传递、对称)实现。
    Object
    中的默认实现已经遵守这些约定,但是如果希望值相等而不是引用相等,则可能需要覆盖它们

  • 对。您可以使用任何对象作为HashMap中的键。为了做到这一点,以下是您必须遵循的步骤

  • 覆盖等于

  • 重写哈希代码

  • java.lang.Object的文档中非常清楚地提到了这两种方法的契约

    是的,HashMap在内部使用hashCode()方法,因此返回正确的值对性能很重要

    下面是HashMap中的hashCode()方法

    public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key.hashCode());
        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))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
    
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }
    
    public V put(K键,V值){
    if(key==null)
    重新
    
    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
    private transient HashMap<E,Object> map;
    
    public boolean add(E e) {
      return map.put(e, PRESENT)==null;
    }