Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.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 equals和hashCode:Objects.hash方法是否已损坏?_Java_Equals_Hashcode - Fatal编程技术网

Java equals和hashCode:Objects.hash方法是否已损坏?

Java equals和hashCode:Objects.hash方法是否已损坏?,java,equals,hashcode,Java,Equals,Hashcode,我使用的是Java7,下面有一个类。我正确地实现了equals和hashCode,但问题是equals在下面的主方法中返回false,而hashCode为两个对象返回相同的哈希代码。我可以用更多的眼睛来观察这门课,看看我是否做错了什么吗 更新:我用自己的哈希函数替换了调用Objects.hash方法的行:chamorro.hashCode()+english.hashCode()+notes.hashCode()。它返回一个不同的哈希代码,这是当两个对象不同时,hashCode应该执行的操作。O

我使用的是Java7,下面有一个类。我正确地实现了
equals
hashCode
,但问题是
equals
在下面的主方法中返回
false
,而
hashCode
为两个对象返回相同的哈希代码。我可以用更多的眼睛来观察这门课,看看我是否做错了什么吗

更新:我用自己的哈希函数替换了调用
Objects.hash
方法的行:
chamorro.hashCode()+english.hashCode()+notes.hashCode()
。它返回一个不同的哈希代码,这是当两个对象不同时,
hashCode
应该执行的操作。
Objects.hash
方法是否已损坏

非常感谢您的帮助

import org.apache.commons.lang3.StringEscapeUtils;

public class ChamorroEntry {

  private String chamorro, english, notes;

  public ChamorroEntry(String chamorro, String english, String notes) {
    this.chamorro = StringEscapeUtils.unescapeHtml4(chamorro.trim());
    this.english = StringEscapeUtils.unescapeHtml4(english.trim());
    this.notes = notes.trim();
  }

  @Override
  public boolean equals(Object object) {
    if (!(object instanceof ChamorroEntry)) {
      return false;
    }
    if (this == object) {
      return true;
    }
    ChamorroEntry entry = (ChamorroEntry) object;
    return chamorro.equals(entry.chamorro) && english.equals(entry.english)
        && notes.equals(entry.notes);
  }

  @Override
  public int hashCode() {
    return java.util.Objects.hash(chamorro, english, notes);
  }

  public static void main(String... args) {
    ChamorroEntry entry1 = new ChamorroEntry("Åguigan", "Second island south of Saipan. Åguihan.", "");
    ChamorroEntry entry2 = new ChamorroEntry("Åguihan", "Second island south of Saipan. Åguigan.", "");
    System.err.println(entry1.equals(entry2)); // returns false
    System.err.println(entry1.hashCode() + "\n" + entry2.hashCode()); // returns same hash code!
  }
}

不要求不相等的对象必须具有不同的哈希代码。相等的对象应具有相等的哈希代码,但不禁止哈希冲突<代码>返回1将是hashCode的一个完全合法的实现,如果不是非常有用的话


可能的散列码只有32位,而且可能的对象数量是无限的:)冲突有时会发生。

两个不相等的对象没有必要有不同的散列,重要的是对两个相等的对象有相同的散列

我可以这样实现hashCode():

public int hashCode() {
    return 5;
}

它将保持正确(但效率低下)。

事实上,你碰巧触发了纯粹的巧合。:)

Objects.hash
恰好是通过依次添加每个给定对象的hash代码,然后将结果乘以31来实现的,而
String.hashCode
对其每个字符都执行相同的操作。巧合的是,您使用的“English”字符串中的差异与“Chamorro”字符串中的相同差异正好在距离字符串末尾多一个偏移处出现,因此所有内容都完全抵消了。恭喜你


尝试使用其他字符串,您可能会发现它按预期工作。正如其他人已经指出的那样,严格地说,这种效果实际上并不是错误的,因为哈希代码可能会正确地发生冲突,即使它们所表示的对象不相等。如果有什么不同的话,也许值得尝试寻找一个更有效的散列,但我几乎不认为在现实情况下有必要这样做。

散列码是32位int值,总是有冲突的可能性(两个对象使用相同的散列码),但它是罕见的/巧合的你们的例子就是这样一个高度巧合的例子之一。这是解释

当您调用
Objects.hash
时,它会在内部调用
Arrays.hashCode()
,逻辑如下:

public static int hashCode(Object a[]) {
    if (a == null)
        return 0;
    int result = 1;
    for (Object element : a)
        result = 31 * result + (element == null ? 0 : element.hashCode());
    return result;
}
对于3参数哈希代码,其结果如下:

   31 * (31 * (31 *1 +hashOfString1)+hashOfString2) + hashOfString3
作为你的第一个目标。单个字符串的哈希值为:

查莫罗-->1140493257 英语-->1698758127 注释-->0

对于第二个对象:

查莫罗-->1140494218 英语-->1698728336 注释-->0

如果您注意到,两个对象中哈希代码的前两个值是不同的。

但当它将最终哈希代码计算为:

  int hashCode1 = 31*(31*(31+1140493257) + 1698758127)+0;
  int hashCode2 = 31*(31*(31+1140494218) + 1698728336)+0;
由于
int
存储在32位中,因此它会产生相同的哈希代码
1919283673

使用以下代码段验证您自己的理论:

  public static void main(String... args) {
    ChamorroEntry entry1 = new ChamorroEntry("&Aring;guigan", 
                         "Second island south of Saipan. &Aring;guihan.", "");
    ChamorroEntry entry2 = new ChamorroEntry("&Aring;guihan", 
                         "Second island south of Saipan. &Aring;guigan.", "");
    System.out.println(entry1.equals(entry2)); // returns false
    System.out.println("&Aring;guigan".hashCode());
    System.out.println("&Aring;guihan".hashCode());
    System.out.println("Second island south of Saipan. &Aring;guihan.".hashCode());
    System.out.println("Second island south of Saipan. &Aring;guigan.".hashCode());
    System.out.println("".hashCode());
    System.out.println("".hashCode());
    int hashCode1 = 31*(31*(31+1140493257) + 1698758127)+0;
    int hashCode2 = 31*(31*(31+1140494218) + 1698728336)+0;
    System.out.println(entry1.hashCode() + "\n" + entry2.hashCode()); 
    System.out.println(getHashCode(
                    new String[]{entry1.chamorro, entry1.english, entry1.notes}) 
                    + "\n" + getHashCode(
                    new String[]{entry2.chamorro, entry2.english, entry2.notes})); 
    System.out.println(hashCode1 + "\n" + hashCode2); // returns same hash code!
  }

    public static int getHashCode(Object a[]) {
        if (a == null)
            return 0;
        int result = 1;
        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());
        return result;
    }

如果您使用了一些不同的字符串参数,希望它会产生不同的哈希代码。

两个对象具有相同的哈希代码但仍然不相等是可以的。所以问题不在于
对象。hash
,对吗?@RayToal这很好,但很愚蠢。假设有40亿个可能的值,碰撞应该是非常快的,您不应该通过手动尝试几个值来遇到它们<代码>对象。哈希在设计上有点愚蠢,因为重复使用相同的乘数是导致这种效率低下的原因。