本文以HashSet为例,描述在hash数据结构中使用类时,类必须同时实现hashcode()方法与equals()方法的原因,有描述不准确的地方,还请不吝指正。
有一个Student类,类有属性:id和phonenumber,id是唯一的,每个同学有一个唯一的id.
用一个HashSet存放班上所有的同学,在同学的电话号码变化后,采用set.add(new Student(id,newPhoneNumber))的方式
覆盖之前的学生记录,达到更新同学电话号码的目的。(当然,也可以从set中取到对应ID的Student对象再修改电话号码,此处采用直接用新实例覆盖的方式,便于说明hashcode()和equals()的作用)
要采用直接set.add()的方式更新学生电话号码,就必须在Student类中,以id为基准,重载hashCode()和equals()方法,即只要id相同,equals()方法就返回true;hashcode()方法产生code时只以id为基准产生。否则,set中就可能存在多个id相同的student对象。
原因是:(以拉链法解决冲突的hash表为例)
hashset.add(student),需要通过对象student的hashcode值查找其指向的链表,之后,再通过equals()方法在链表中找equals()查找是否有equals()返回为true的对象。
若对象student的hashcode无对应链表,hash表中新增code及对应链表,链表中存储student对象。
若对象student的hashcode有对应链表,但在链表中未找到equals()返回为true的对象,则将student对象插入该链表。
若对象student的hashcode有对应链表,且存在equals()返回为true的对象,则将该对象更换为student。
如果Student类不实现hashcode()方法,则使用Object的hashcode()方法产生对象的hashcode值,该值是通过对象的内存地址算出来的,是唯一的。
此种情况下,每一个Student类对象的hashcode值都是不一样的,那么即使在Hashset中存在id相同的student对象,也无法找到,
采用set.add(new Student(id,newPhoneNumber))方式,就无法覆盖相同id的对象。
如果不实现equals()方法,则使用Object的equals()方法,即使用对象的内存地址比对是否为同一对象。
同理,new出来的id相同的student对象,其equals()不会为true,采用set.add(new Student(id,newPhoneNumber))方式,也就无法覆盖相同id的对象。
因此,若要在Hash数据结构中,比如HashSet,HashMap中存储对象,该对象必须重载hashcode()方法和equals()方法。
由于hashcode()方法实现不好,会导致hash值冲突,以拉链法解决冲突的hash表为例,极端情况下会导致成为单链表,降低hash查找效率。
因此,可采用eclipse中自动生成hashcode()的方法:"Source"->"Generate HashCode() And equals()",然后选择要判重的对象属性,点击"OK",就可以了。