有时候一些东西不经意听见了,并不当回事,回头就忘了。人总是这么健忘!
学习hebernate的时候,看到一句话,对于需要映射到数据库中的实体类需要满足几个要求,其中有一个是说对于重写了equals重写后要重写hashcode。相信这是一句老生常谈的话了,大家都不陌生。当时我也一扫而过。后来看到一个短片说怎样验证一个cookie有效性也提到了hash算法。于是就想验证一下之前的两个重写。
当时随手就写了一段代码(没有用快捷键),如下:
1 public class hash { 2 public static void main(String[] args) { 3 4 HashSet<Student> hs = new HashSet<Student>(); 5 Student stu1 = new Student("zhang"); 6 Student stu2 = new Student("zhang"); 7 8 hs.add(stu1); 9 hs.add(stu2); 10 System.out.println(hs.size()); 11 } 12 } 13 14 class Student { 15 String name; 16 17 Student( String name) { 18 this.name = name; 19 } 20 21 // @Override 22 // public int hashCode() { 23 // // TODO Auto-generated method stub 24 // final int INDEX = 12345; 25 // return name.hashCode()*INDEX; 26 // }假若不覆盖hashcode方法会怎样啦!将会发现两个对象stu1和stu2我们期望是同一个,不用存进来了,但是在hash值这一关就没有过,new对象时默认以对象的内存地址映射hash值,也就是new了两个对象的hash值是不同的, 27 28 //因此我们需要覆盖hashcode(),让它按我们的期望来返回hash值 29 30 public int hashcode() { 31 32 final int INDEX = 12345; 33 return name.hashCode()*INDEX; 34 } 35 36 37 public boolean equals(Student stu ) { 38 39 if(this.name.equals(stu.name)){ 40 return true; 41 } 42 return false; 43 } 44 }
我期望是结果是set中只插入一个,但结果总是两个,搞得我都有点怀疑set插入的判断过程了,难道不是像记忆中的那样首先判断hash值,如果相等就判断equals,若equals相等就是说明是同一个,就不插入吗!郁闷了半天搞得。后来我说打印一下hash值看一下啦,结果吓我一大跳,怎么有两个.hashcode()方法,难道是我眼花吗,再仔细一看,打自己耳光的心都有,怎么可以将hashCode()写成hashcode(),赶紧改过来,但还是不对,问题又在哪里啦,这不是坑吗,短短的几行代码,为什么就是不能按我的想法来啦,郁闷。一共就两个方法,那在看看是不是equals啦,好吧,懒得自己写了,还是用快捷键了,一个alt+shift+s,覆盖equals看看,结果又让我不爽了,我的刚才的那个equals怎么就是Student参数啦,好吧,对自己无语了(说到这里就顺带说一下overload和override,前者是在同一个类中根据参数的不同重载,后面的是子类覆盖父类的方法,除了方法体里的东西不一样外,其余的都一样)。赶快修改过来,再运行,出现了自己想要的结果。
1 public class hash { 2 public static void main(String[] args) { 3 4 HashSet<Student> hs = new HashSet<Student>(); 5 Student stu1 = new Student("zhang"); 6 Student stu2 = new Student("zhang"); 7 8 hs.add(stu1); 9 hs.add(stu2); 10 System.out.println(hs.size()); 11 } 12 } 13 14 class Student { 15 String name; 16 17 Student( String name) { 18 this.name = name; 19 } 20 21 // @Override 22 // public int hashCode() { 23 // // TODO Auto-generated method stub 24 // final int INDEX = 12345; 25 // return name.hashCode()*INDEX; 26 // }假若不覆盖hashcode方法会怎样啦!将会发现两个对象stu1和stu2我们期望是同一个,不用存进来了,但是在hash值这一关就没有过,new对象时默认以对象的内存地址映射hash值,也就是new了两个对象的hash值是不同的, 27 28 //因此我们需要覆盖hashcode(),让它按我们的期望来返回hash值 29 @Override 30 public int hashCode() { 31 // TODO Auto-generated method stub 32 final int INDEX = 12345; 33 return name.hashCode()*INDEX; 34 } 35 36 @Override 37 public boolean equals(Object obj) { 38 // TODO Auto-generated method stub 39 Student stu =(Student)obj; 40 if(this.name.equals(stu.name)){ 41 return true; 42 } 43 return false; 44 } 45 }
下面就说说如果我们不覆盖hashcode会是什么后果啦。按照我们的想法,stu1和stu2有同样的名字是同一个人,我们希望不要同时都放到set中,但是我们如果不覆盖hashcode,在new对象的时候就会将对象的内存地址映射成hash值,就会导致两个对象拥有不同的hash值,当然这不是我们想要的结果,所以我们需要覆盖上诉的两个方法次啊是完整的。