Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 对于有效的散列键,overrided equals不是必需的_Java_Hashmap_Key_Equals_Hashcode - Fatal编程技术网

Java 对于有效的散列键,overrided equals不是必需的

Java 对于有效的散列键,overrided equals不是必需的,java,hashmap,key,equals,hashcode,Java,Hashmap,Key,Equals,Hashcode,在我看到的所有关于重写equals和hashcode方法的问题中,人们总是说,如果重写equals方法,那么也应该重写hashcode方法,反之亦然,以避免从哈希集合获取对象时出现问题 P> >我个人认为,反之亦然,为了这个目的,让我们考虑在HASMAP中使用一个对象(带有属性)作为密钥,而不需要测试该对象的两个实例之间的相等性。 如果我们以有效的方式覆盖hashcode方法(基于属性和其他规则),那么我们可以拥有唯一的键,在这种情况下,对于HashMap,我们在每个bucket中都有一个唯一的

在我看到的所有关于重写equals和hashcode方法的问题中,人们总是说,如果重写equals方法,那么也应该重写hashcode方法,反之亦然,以避免从哈希集合获取对象时出现问题

P> >我个人认为,反之亦然,为了这个目的,让我们考虑在HASMAP中使用一个对象(带有属性)作为密钥,而不需要测试该对象的两个实例之间的相等性。 如果我们以有效的方式覆盖hashcode方法(基于属性和其他规则),那么我们可以拥有唯一的键,在这种情况下,对于HashMap,我们在每个bucket中都有一个唯一的值,HashMap不会使用equals方法来比较bucket中的值,因为每个bucket中都有一个值

合同方:

  • 我们对象的两个实例是equals(object.equals 1)意味着它们具有相同的引用,并且基于我们的hashcode方法,hashcode将是相同的==>OK
  • 不同的hashcode会导致不相等的objects==>NOK(在我们的例子中,有可能打破这个规则),但是由于我们有好的hashing键(我们的场景目的),契约实际上并不重要
我错了吗

编辑:(搜索后,在答案下方,并查看HashMap的源代码)

为什么我们还要重写equals方法

初始条件、唯一哈希代码和不重写equals()

  • 使用get()方法检索值时出现问题:
equals()执行引用比较,该方法用于方法put和get

public V get(Object key) {
    if (key == null)
        return getForNullKey();
    int hash = hash(key.hashCode());
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
            e != null;
            e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
            return e.value;
    }
    return null;
}
如果我们想根据Baron Steven的帐号检索他的帐号,我们不能只创建一个具有相同帐号的新对象,比如Instance88Obj(144756696)并调用get方法来检索该值。在这种情况下,结果将是null,因为get方法使用基于键引用的比较,即使hashcode相同

  • 使用put()方法更新值问题:
如果未重写equals,则通过新实例键(但具有相同的哈希代码)放置新值以更新它将不起作用,只会添加另一对键/值:

First put: [key:Instance1Obj(144756696),  value:Person1Obj(“Baron”, “Seven”)]
Second put: [key:Instance2Obj(144756696),  value:Person2Obj(“Baron”, “Steven”)]
通常我们希望用“Steven”替换值“Seven”,但这种替换不会发生

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)
返回putForNullKey(值);
int hash=hash(key.hashCode());
int i=indexFor(散列,table.length);
for(条目e=表[i];e!=null;e=e.next){
对象k;
如果(e.hash==hash&((k=e.key)==key | | key.equals(k))){
V oldValue=e.value;
e、 价值=价值;
e、 记录存取(本);
返回旧值;
}
}
modCount++;
加法器(散列、键、值、i);
返回null;
}
结论:

==>如果覆盖hashcode,也会覆盖equals

==>如果重写equals,也重写hashcode。(本主题除外:)


如果您的类使用
Object
中的
equals
方法,则任何幂等
hashCode
实现都可以。如果它使用了除
对象
以外的超类中的
equals
方法,那么您需要确保您的
hashCode
实现与之兼容。

可以避免实现equals,也可以避免实现hashCode。在这两种情况下,你都会让自己面对一个充满潜在痛苦的世界。毕竟要记住,散列是用来将对象分割成bucket的,然后bucket中的对象需要检查是否相等。尽管如此,您仍然依赖于正在使用的集合对象,它们的行为完全符合您的需要


这些指导原则是为了防止出现很多问题,除了尝试和变得聪明之外,没有什么好的理由可以避免遵循这些指导原则,这样做会让你自己在未来面临大量问题。

不同的哈希代码会导致不相等的对象==>它说的是“引导”,而不是说“总是”。两个相等的对象总是返回相同的哈希代码,但是如果没有重写hashcode方法,两个不相等的对象几乎不会返回相同的哈希代码

合同规定,如果两个对象相等,则它们应该具有相同的哈希代码。但除此之外,如果不相等的对象应该有不同的哈希代码,则哈希表工作得最好

如果覆盖默认的
hashCode
方法而不覆盖默认的
equals
方法,则可能会使
hashCode
的行为次优;i、 e.给出hashCode为不相等的对象返回相同值的更多情况。这可能会导致哈希表中出现更多冲突,具体取决于
hashCode
覆盖的详细信息以及应用程序使用的实例。最终结果将是业绩显著下降


因此,虽然正确的应用程序行为并不严格要求“反之亦然”,但该建议总体上仍然有效。最好是
equal
hashCode
方法具有匹配的语义

哈希代码的值空间比哈希映射中的桶数大几个数量级。因此,除非我们讨论像
EnumMap
这样的专门的
Map
实现,否则即使给定了完美的哈希代码,每个bucket也总会有多个对象

不重写
equals()
的对象只有在它们是完全相同的对象时才会被视为相等,而不管它们的字段值如何。因此,只重写
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;
}