Java中HashSet添加两个对象,这两个对象的equals()方法返回true并且它们具有相同的hashcode。

3

frequencySet()方法用于在一个Integer[]中计算每个字符在一个String中出现的频率,这个Integer[]被封装到Counter类中,该类重写了equals和hashcode方法。该方法应该只返回一个唯一的频率集合,但是它添加了两个Counter对象。

从打印语句可以看出:hashcode()返回相等的值,并且equals()返回true

问题出在哪里?


class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        // your code goes here
        String[] a = new String[2];
        a[0]="tan";
        a[1]="nat";
        Set<Counter>  s = frequencySet(a);
        System.out.println(s.size()); // prints
        System.out.println(getFreq(a[0]).equals(getFreq(a[1])) + ":" + getFreq(a[0]).hashcode() + ":" + getFreq(a[1]).hashcode() );
    }
public static Set<Counter> frequencySet(String[] strs) {
        Set<Counter> set =  new HashSet<>();
        for(String s: strs){
            Counter counter = getFreq(s);
            set.add(counter);
            //System.out.println(s + " : " + counter.hashcode() + " : " + Arrays.toString(counter.arr) );
        }
        return set;
    }
    
    private static  Counter getFreq(String s){
        Integer[] frequency = new Integer[26];
        for(char c : s.toCharArray()){
            Integer  a =  frequency[c-'a'];
            if(frequency[c-'a']==null){
                frequency[c-'a']=1;
            }
            else{
                a++;
                frequency[c-'a']=a; //++frequency[c-'a'];  
            }
        }
        //System
        return new Counter(frequency);
    }
}
    class Counter{
        Integer[] arr;
        public Counter(Integer[] arr){
            this.arr=arr;
        }
        
        public int hashcode(){
            //return Arrays.deepHashCode((Integer[])arr);
            int hashcode=31;
            for(int i=0;i<arr.length;i++){
                if(arr[i]==null)
                    hashcode+=i;
                else
                    hashcode+=31*arr[i];
            }
            return hashcode;
        }
        
        public boolean equals(Object o){
            //return Arrays.deepEquals(arr,(Integer[])o);
            Counter c = (Counter)o;
            Integer[] other = c.arr;
            for(int i=0;i<26;i++){
                if((arr[i]==null && other[i]!=null) || (arr[i]!=null && other[i]==null)){
                    return false;
                }
                else if(arr[i]!=null && other[i]!=null && arr[i]!=other[i]){
                    return false;
                }
            }
            return true;
        }
    }

输出:

    2
    true:417:417

<script src="https://ideone.com/e.js/s2LcBw" type="text/javascript" ></script>

2个回答

6

请始终使用 @Override。您已经实现了方法 public int hashcode()。那不是您认为的东西。您需要 public int hashCode()。请注意大写字母 c。添加 @Override 注释,编译器将报错(首先尝试一下:@Override public int hashcode()...,然后编译它,注意错误,并通过使其成为 hashCode 来修复它)。

请注意,您的 hashCode 实现非常低效和奇怪。您可能听说过质数的某些内容,但未正确实现它。正确的方法是,如果必须,将 哈希代码 乘以质数,而不是下一个元素值。

更一般地说,Arrays.deepHashCode 在这里完全可以使用。我假设发生了以下情况:

  • 您使用 deepHashCode 编写了 hashcode 实现。
  • 代码不起作用。
  • 您(错误地)将 deepHashCode 归咎为罪魁祸首,并编写了自己的哈希程序。
  • 它仍然无法工作-逻辑上是错误的,因为那不是问题所在(使用小写字母 c 编写 hashcode 才是问题)。

撤消您的“修复”-此代码使用 deepHashCode 更易于阅读和更有效。


没错,这就是你描述的场景发生了。我写的 hashcode 实现只是一些天真的东西来进行检查。打字错误会浪费很多时间 :) 它是一个教训,如果你想要节省一些好的时间,就要使用 @Override。 - nanosoft

2

您在hashcode()中有一个拼写错误,它应该改为hashCode()。您可以通过添加Override注释来捕获此错误,在这种情况下,编译器将通知您:

@Override
public int hashCode() {

@Override
public boolean equals(Object o) {

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接