是这样的.....当你的元素存入HashSet集合的时候,他会自动去调用你的元素所在类的hashCode()方法.如果hashCode()的返回值的结果相同.则会再去比较equals的结果.我们如果存入的是字符串这种JDK意境定义好了
的类的话.那么里面的hashCode()和equals方法都是已经重写完毕了的.所以是能保证元素唯一性的.
但是我们如果在hashSet里面去存储自定义类的元素的话,那么就会发现相同的元素也存储进去了.这是因为我们能没有
重写hashCode()和equals()的关系.我们自定义的类,因为是继承自Object类,所以里面的hashCode()和equals方法也是来自于Object,而Object类里面的hashCode()方法产生的值和地址值有关系,和其他的原因没有太大的关系,这就让我们很困扰,因为你new 出来的两个对象,地址值当然是不一样的.但是其实两个学生是相同的学生,比较的并不是地址值,所以我们就要去重写hashCode()方法.让这个方法比较的东西是和学生相关的.所以才有了
return name.hashCode()+age*31;对吧.如果是用eclipse生成的话就会更多更麻烦.但是你不用去想为什么代码要那样的写.你只需要明白,hashCode()方法我们重写他就是想要这个方法比较两个元素是否相同,比的是我们在意的属性而不是地址值.而equals方法的复写一直都是那三个步骤
1 提高效率 (this == obj) 这是在避免你传入的元素就是你自己,因为 == 比较的是地址值嘛 对吧.如果你传自己
当然相同. 直接return true
2 提高程序的健壮性 (!(obj instanceof Student) )即判断你传入的元素是不是我们要比较的学生类,如果你这里不做这个判断的话,也是没有关系的.只是如果传入的类型错误后面就会有类型转换异常,即ClassCastException.
3 强转然后比较 Student s = (Student) obj;
return this.name.equals(s.name) && this.age == s.age;
这里的代码之所以这么写,就是因为我们判断两个学生是否是同一个学生的基本条件就是年龄和姓名,如果你有其他的元素可以自己继续添加.前面equals是因为字符串的比较嘛 所以用equals 后面是年龄,因为是基本类型int的比较
所以用 == 底层就是先判断hashCode(),再判断equals,如果都相同,就是为是同一个元素,不添加进去.为什么hashCode()要写的那么的复杂呢,是因为hashCode()的判断效率要高于equals(),尽量在hashCode()就判断出两个元素是不是一个,少走equals步骤.所以才将hashCode()的方法里面写的很复杂,你不要完全理解,只需知道就是通过成员变量在判断两个元素是不是一个即可. |