我正在尝试创建一组整数数组,问题是如果我尝试这样做:
HashSet<int[]> s = new HashSet<int[]>();
int a1[] = {1,2,3};
int a2[] = {1,2,3};
s.add(a1);
s.add(a2)
System.out.println(s.size());
然后s有两个对象,但应该只有一个。
注意:它不管是HashSet< Integer[]>也是一样的。它就是不能正常工作。
现在,如果我尝试使用ArrayList< Integer>来做这件事:
HashSet<ArrayList<Integer>> s = new HashSet<ArrayList<Integer>>();
ArrayList<Integer> a1 = new ArrayList<Integer>();
ArrayList<Integer> a2 = new ArrayList<Integer>();
a1.add(1);
a1.add(2);
a1.add(3);
a2.add(1);
a2.add(2);
a2.add(3);
s.add(a1);
s.add(a2)
System.out.println(s.size());
那么s就只有一个对象。
我想到了一种避免第一段代码中错误的方法,将每个数组的哈希码存储在一个哈希集合中,如下所示:
int a1[] = {0,10083,10084,1,0,1,10083,0,0,0,0};
int a2[] = {1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0,2112};
HashSet<Integer> s= new HashSet<Integer>();//hashcodes of each array
s.add(Arrays.hashCode(a1));
s.add(Arrays.hashCode(a2));
System.out.println(Arrays.hashCode(a1));
System.out.println(Arrays.hashCode(a2));
System.out.println(s.size());
它适用于第一种情况(1,2,3),但在存在碰撞的情况下,它不起作用,因此我必须处理碰撞。所以,我认为我正在自己实现一个HashSet。
使用HashSet< ArrayList< Integer>> 它完美地工作。我想Java在这种情况下管理碰撞。
我的问题是,为什么Java不允许管理一个HashSet< int[]>或HashSet< Integer[]>,如果生成的哈希码与ArrayList< Integer>中的相同,并且数组的哈希码可以通过调用Arrays.hashCode(...)来简单计算。
最后,如果我想做一个HashSet< int[]>(或HashSet< Integer[]>),我必须自己实现它吗?还是有更好的方法来做到这一点?
谢谢。
更新: 好的,最终我认为我得出了一个完整的答案。正如@ZiyaoWei和@user1676075所评论的那样,它不起作用是因为equals返回false且哈希码不同。但是,为什么Java不重写这些方法(使用Arrays.equals(),Arrays.hashCode()),以便可以做到HashSet< int[]>之类的事情呢?答案是因为数组是可变对象,并且根据哈希码的通用契约,哈希码不能取决于可变值(数组的每个元素都是可变值)。可变对象和哈希码
在这里有关于在hashCode中使用可变字段的好解释 http://blog.mgm-tp.com/2012/03/hashset-java-puzzler/ 以及在hashmaps中使用可变键的讨论 可变hashmap键是否危险?
我的答案是,如果你想使用HashSet<int[]>,你需要创建一个包含数组的类,并且如果你希望hashcode和equals依赖于值,则应该使用Arrays.equals()和Arrays.hashCode()重写这些方法。如果你不想违反契约,只需将数组设为final。谢谢大家!