如果我们只覆盖类中的hashCode()并在Set中使用它会发生什么? [英] What happens if we override only hashCode() in a class and use it in a Set?

查看:137
本文介绍了如果我们只覆盖类中的hashCode()并在Set中使用它会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能不是现实世界的场景,但只是想知道会发生什么,下面是代码。

This may not be the real world scenario but just curious to know what happens, below is the code.

我正在创建一组类<$的对象C $ C> UsingSet 。
根据Java中的哈希概念,当我第一次添加包含a的对象时,它将创建一个带有哈希码97的桶并将对象放入其中。
再次遇到带有a的对象时,它会在UsingSet类中调用重写的hashcode方法,它会得到hashcode 97,接下来是什么?

I am creating a set of object of class UsingSet. According to hashing concept in Java, when I first add object which contains "a", it will create a bucket with hashcode 97 and put the object inside it. Again when it encounters an object with "a", it will call the overridden hashcode method in the class UsingSet and it will get hashcode 97 so what is next?

由于我没有覆盖equals方法,默认实现将返回false。那么具有值a的Object将保留在哪个存储区中的前一个对象保存的同一个存储区中?还是会创造新的桶?
任何人都知道它将如何在内部存储?

As I have not overridden equals method, the default implementation will return false. So where will be the Object with value "a" be kept, in the same bucket where the previous object with hashcode 97 kept? or will it create new bucket? anybody know how it will be stored internally?

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;

class UsingSet {  

  String value;  

  public UsingSet(String value){  
    this.value = value;  
  }  

  public String toString() {  
    return value;  
  }  

  public int hashCode() {  
    int hash = value.hashCode();  
    System.out.println("hashcode called" + hash);  
    return hash;  
  }  

  public static void main(String args[]) {  

    java.util.Set s = new java.util.HashSet();  

    s.add(new UsingSet("A"));  
    s.add(new UsingSet("b"));  
    s.add(new UsingSet("a"));  
    s.add(new UsingSet("b"));   
    s.add(new UsingSet("a"));  

    s.add(new Integer(1));  
    s.add(new Integer(1));  

    System.out.println("s = " + s); 

  }  
}  

输出为:

hashcode called65
hashcode called98
hashcode called97
hashcode called98
hashcode called97
s = [1, b, b, A, a, a]


推荐答案

詹姆斯大回答是不正确的,或者说是误导(部分不正确)。我将解释。

James Large answer is incorrect, or rather misleading (and part incorrect as well). I will explain.

如果两个对象根据equals()方法相等,它们也必须具有相同的哈希码。
如果两个对象具有相同的哈希码,它们也不必相等。

If two objects are equal according to their equals() method, they must also have the same hash code. If two objects have the same hash code, they do NOT have to be equal too.

这是java.util.Object文档中的实际写法:

Here is the actual wording from the java.util.Object documentation:



  • 如果两个对象根据equals(Object)方法相等,则调用hashCode方法两个对象中的每一个都必须产生相同的整数结果。

  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要调用hashCode对两个对象中的每一个的方法必须产生不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。

如果两个对象没有相同的哈希,那么它们就不是等于。但是,散列不是检查相等性的一种方法 - 所以说它是检查相等性的更快方法是非常不正确的。

It is true, that if two objects don't have the same hash then they are not equal. However, hashing is not a way to check equality - so it is wildly incorrect to say that it is a faster way to check equality.

此外,它也非常不正确说hashCode函数是一种有效的方法。这完全取决于实现,但是当String变大时,字符串的hashCode的默认实现效率非常低。它将根据String的每个char执行计算,因此如果您使用大型字符串作为键,那么这将变得非常低效;更多,如果你有大量的桶。

Also, it is also wildly incorrect to say the hashCode function is an efficient way to do anything. This is all up to implementation, but the default implementation for hashCode of a string is very inefficient as the String gets large. It will perform a calculation based on each char of the String, so if you are using large Strings as keys, then this becomes very inefficient; moreso if you have a large number of buckets.

在Map(HashSet内部使用HashMap)中,有一些桶,每个桶中都有一个链表。 Java使用hashCode()函数来找出它所属的桶(它实际上将修改哈希值,具体取决于存在多少桶)。由于两个对象可以共享相同的哈希,因此它将依次遍历链表,检查equals()方法以查看该对象是否重复。根据java.util.Set文档:

In a Map (HashSet uses a HashMap internally), there are buckets and in each bucket is a linked list. Java uses the hashCode() function to find out which bucket it belongs in (it actually will modify the hash, depending on how many buckets exist). Since two objects may share the same hash, it will iterate through the linked list sequentially next, checking the equals() method to see if the object is a duplicate. Per the java.util.Set documenation:


不包含重复元素的集合。

A collection that contains no duplicate elements.

因此,如果它的hashCode()将它引导到一个存储桶,其中该存储桶包含一个对象,其中.equals()的计算结果为true,那么之前的Object将被覆盖新对象。您可以在此处查看更多信息:
Java HashMap如何使用相同的哈希码处理不同的对象?

So, if its hashCode() leads it to a bucket, in which that bucket contains an Object where the .equals() evaluates to true, then the previous Object is overwritten with the new Object. You can probably view here for more information: How does a Java HashMap handle different objects with the same hash code?

一般来说,如果你覆盖hashCode函数,你也会覆盖equals函数,这是一个好习惯。 (如果我没有弄错的话,如果你选择不这样做,就会违反合同。)

Generally speaking though, it is good practice that if you overwrite the hashCode function, you also overwrite the equals function (if I'm not mistaken, this breaks the contract if you choose not to).

这篇关于如果我们只覆盖类中的hashCode()并在Set中使用它会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆