关于hashcode的那些有趣的事情

hashcode的作用是让基于散列的集合正常的运行,这些散列的集合有:HashSet、HashMap以及HashTable。
举个例子:当我们需要添加一个元素的时候a进Set的时候,我们会先取出a的hashcode,然后在散列桶里边找有没有散列值跟a这个元素的散列值相同的,没有的话,最直接添加;有的话,再用equals方法判断,添加的值。

有趣的例子1:可变数据类型的操作改变,导致哈希值的改变

    List<String> list = new ArrayList<>();
    list.add("a");
    Set<List<String>> set = new HashSet<>();
    set.add(list);//把list添加到set里
    System.out.println(set.contains(list));//true
    list.add("b");//对list进行操作
    list.add("c");
    System.out.println(set.contains(list));//false,为什么不是true

简述:
??

有趣的例子2 重写equals方法要重写hashcode
比较有两种方式行为比较和观察比较,为了满足我们需要的比较,我们改写equals方法,下面是代码

 public static void main(String args[]){
    Set<Student> s = new HashSet<>();
    s.add(new Student("a","b"));
    System.out.println("添加完毕");
    System.out.println(s.contains(new Student("a","b")));
  }
public class Student{
  public final String start;
  public final String stop;
  public Student(String start,String stop) {
    this.start = start;
    this.stop = stop;
  }  
  @Override
  public boolean equals(Object s) {
    if(!(s instanceof Student)) {
      return false;
    } 
    Student ss = (Student) s;
    System.out.println("equals方法被调用啦");
    return start.equals(ss.start) && stop.equals(ss.stop);
  }
}

但是结果却是false,这是因为前边说过,判断是否包含,需要判断hashcode是否相等,再使用equals,这里我们虽然重写了equals方法,但是由于是两个new,他们的地址肯定不同(即hashcode不相同),运行可以得到验证

所以还要再重写hashcode,在Student里边添加下面代码

@Override 
public int hashCode() {
    int result = 17;
    result = 31*result + start.hashCode();
    result = 31*result + stop.hashCode();
    System.out.println("hashcode方法被调用啦"+" "+"hashcode: "+result);
    return result; 
}

这里还有一个很有意思的验证,验证了set使用contains判断是否包含的步骤是怎么样的,再次运行,打印出来的结果是:

hashcode方法被调用啦 hashcode: 19442
添加完毕
hashcode方法被调用啦 hashcode: 19442
equals方法被调用啦
true

说明每次new都回去查看这个new的散列值,当处理contains的时候,就拿第二个new的值,去跟set所有的散列值比,如果相同的话,就继续调用equals

猜你喜欢

转载自blog.csdn.net/leafdown_/article/details/80644639
今日推荐