Set如何检查重复项? Java HashSet

问题描述 投票:-2回答:4

对于以下代码,它输出“1”。和第二个代码输出“2”我不明白为什么会发生这种情况。是因为我要添加相同的对象吗?我该如何实现所需的输出2。

import java.util.*;
public class maptest {
public static void main(String[] args) {
    Set<Integer[]> set = new HashSet<Integer[]>();
    Integer[] t = new Integer[2];
    t[0] = t[1] = 1;
    set.add(t);
    Integer[] t1 = new Integer[2];
    t[0] = t[1] = 0;
    set.add(t);
    System.out.println(set.size());

   }
}

第二代码:

import java.util.*;
public class maptest {
public static void main(String[] args) {
    Set<Integer[]> set = new HashSet<Integer[]>();
    Integer[] t = new Integer[2];
    t[0] = t[1] = 1;
    set.add(t);
    Integer[] t1 = new Integer[2];
    t1[0] = t1[1] = 1;
    set.add(t1);
    System.out.println(set.size());

    }
}
java set hashset
4个回答
1
投票

Set实现可能调用t.hashCode(),因为数组不会覆盖Object.hashCode方法,所以同一个对象将具有相同的哈希码。因此,更改数组的内容不会影响其哈希代码。要正确获取数组的哈希码,您应该调用Arrays.hashCode

不管怎么说,你不应该把可变内容放在集合中,所以我建议你把不可变列表放到集合中。如果你想坚持使用数组,只需像使用t1一样创建一个新数组,并将其放入集合中。

编辑:

对于代码2,tt1是两个不同的数组,因此它们的哈希码是不同的。同样,因为hashCode方法没有在数组中被覆盖。数组的内容不会影响哈希码,无论它们是否相同。


2
投票

Set只包含不同的元素(它的本质)。基本的实现,HashSet,使用hashCode()首先找到一个包含值的桶然后equals(Object)来寻找一个不同的值。

数组很简单:它们的hashCode()使用默认值,继承自Object,因此取决于引用。 equals(Object)也与Object相同:它仅检查识别,即:引用必须等于。

定义为Java:

public boolean equals(Object other) {
  return other == this;
}

如果你想要放置不同的数组,你必须要试试运气TreeSetComparator的正确实现,要么包装你的数组或使用List或另一个Set

Set<List<Integer[]>> set = new HashSet<>();
Integer[] t = new Integer[]{1, 1};
set.add(Arrays.asList(t));
Integer[] t1 = new Integer[]{1, 1};
set.add(Arrays.asList(t1));
System.out.println(set.size());

至于SetMap密钥中使用的对象的可变性:

  • boolean equals(Object)使用的字段不应该被静音,因为静音对象可能等于另一个。 Set不再包含不同的值。
  • int hashCode()使用的字段不应该为基于散列的集合(HashSetHashMap)静音,因为如上所述,它们通过将项目放入桶中来进行操作。如果hashCode()发生变化,那么桶中对象的位置也可能会发生变化:Set将包含相同引用的两倍。
  • 由于与int compareTo(T)相同的原因,Comparator::compare(T,T)equals使用的字段不应该被静音:SortedSet不会知道有变化。

如果需要,你必须首先从集合中删除项目,然后改变它,重新添加它。


2
投票

你将Object添加到Set

不包含重复元素。

你只需要向Object添加一个Set。您只能更改其内容的值。要了解我的意思,请尝试添加System.out.println(set.add(t));

作为add()方法:

如果此set尚未包含指定的元素,则返回true

此外,您的t1与您的第一个代码段完全无关,因为您从未使用它。


在你的第二个代码片段中输出两个因为你在Integer[]中添加了两个不同的Objects Set

尝试打印出Objects的哈希码,看看它是如何工作的:

Integer[] t = new Integer[2];
t[0] = t[1] = 1;
//Before we change the values
System.out.println(t.hashCode());
Integer[] t1 = new Integer[2];
t1[0] = t1[1] = 1;
//After we change the values of t
System.out.println(t.hashCode());
//Hashcode of the second object
System.out.println(t1.hashCode());

输出:

//Hashcode for t is the same before and after modifying data
366712642
366712642
//Hashcode for t1 is different from t; different object
1829164700

1
投票

java.util.Set实现如何检查重复对象取决于实现,但根据Set的文档,“重复”的适当含义是o1.equals(o2)

由于HashSet特别基于哈希表,因此它将通过计算呈现给它的对象的hashCode()来寻找副本,然后遍历相应哈希桶中的所有对象(如果有的话)。

数组不会覆盖hashCode()equals(),因此它们实现实例标识,而不是值标识。因此,无论其元素的值如何,给定的数组总是具有相同的哈希码,并且始终只有equals()本身。第一个代码将相同的数组对象添加到集合中两次。无论其元素的值如何,它仍然是相同的集合。第二个代码将两个不同的数组对象添加到一个集合中。无论其元素的值如何,它们都是不同的对象。

另请注意,如果您有可变对象实现值标识,这样它们的相等和哈希码取决于其成员的值,那么当它是Set的成员时修改这样的对象很可能会打破Set。这是基于每个实现的记录。

© www.soinside.com 2019 - 2024. All rights reserved.