如果我们只覆盖类中的hashCode()并在Set中使用它会发生什么?

kum*_*mar 8 java collections set

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

我正在创建一组类的对象UsingSet.根据Java中的哈希概念,当我第一次添加包含"a"的对象时,它将创建一个带有哈希码97的桶并将对象放入其中.当它遇到带有"a"的对象时,它将在类UsingSet中调用重写的哈希码方法,它将获得哈希码97,那么下一步是什么?

由于我没有覆盖equals方法,因此默认实现将返回false.那么具有值"a"的Object将保留在哪个存储区中,其中保留了哈希码97的前一个对象?还是会创造新的桶?有谁知道它将如何存储在内部?

/* 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); 

  }  
}  
Run Code Online (Sandbox Code Playgroud)

输出是:

hashcode called65
hashcode called98
hashcode called97
hashcode called98
hashcode called97
s = [1, b, b, A, a, a]
Run Code Online (Sandbox Code Playgroud)

sea*_*e27 14

詹姆斯大回答是不正确的,或者更具误导性(并且部分不正确).我会解释.

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

以下是java.util.Object文档中的实际措辞:

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

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

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

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

不包含重复元素的集合.

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

一般来说,最好是如果你覆盖hashCode函数,你也会覆盖equals函数(如果我没有弄错,如果你选择不这样做会破坏契约).


小智 11

HashCode和Equals方法

  1. 仅覆盖HashCode,使用默认值Equals: 只有对同一对象的引用才会返回true.换句话说,通过调用equals方法,您期望相等的那些对象将不相等.
  2. 只有覆盖等于,使用默认的HashCode: HashMap或HashSet中可能存在重复项.我们编写equals方法并期望{"abc", "ABC"}等于.但是,在使用HashMap时,它们可能出现在不同的存储桶中,因此该contains()方法不会相互检测它们.