Q1:为什么要重写equals方法?
在java中new出来的对象obj1,obj2即使是内容完全相同,但在内存中的地址不一样,也就是在heap上分配了两份内存。有时候我们必须比较对象是否已存在,比如HashSet里的值是不能重复的。那怎么判断对象是否一样呢?调用equals方法。比如 obj1!=null && !obj1.eqauls(obj2)。
Q2:如果DO中没有写equals方法,那结果是什么?
java中任何对象都是Object的子类。通过编译java字节码文件时加入"invokespecial java.lang.Object()"来自动引入Object类。如果DO中没有写equals方法,则调用时会调用Object的equals方法,默认就是直接比对两个对象的地址是否一样了,即this == obj。
Q3:平时使用HashMap或者HashSet好像也没写过equals方法呀,什么时候需要写呢?
由于平时都是用String、Integer、Double等类作为key,而这些类中都已经重写好了equals和hashCode方法。如果需要将某个DO作为Key,且将其内容作为"是否重复"的标准(而不是按内存地址比较),则需要自己重写这两个方法。
Q4:如果只重写equals而不重写hashCode,有什么问题?
像HashMap这种集合类,原本有两种做法:
a) 首先是通过eqauls判断key是否存在,然后再根据hash值定位到具体的区域上。
b) 首先根据hash值定位到某个区域上,然后再在区域内进行equals判断
这里的区域其实就是指HashMap的链表。方法a显然不妥,它需要在插入前和元素内的所有元素都比较一次,性能很差。所以HashMap采用的是方法b,先用hash值定位到某个table[i]上,然后再遍历链表,调用equals方法判断元素是否已存在! 回到问题上,如果不重写hashcode,假如obj1被放在table[i]上,根据内存地址obj2很可能被定位到table[j]上,obj2根本没机会和obj1进行equals比较了,即时他们是相同的!即违背了Set无重复元素!
jdk规范中说道,如果要实现自己的equals()方法,则也需要实现相应的hashCode()方法。为什么?这是为了避免在HashMap等hash类使用时出现异常。当然,jdk也不会强制要求你这么做,它只是告诉你,不这么做,出了什么问题,别找它!
所以,一般来讲,A.equals(B) == true 则可以推出 A.hashCode() == B.hashCode(),但是反过来就不行了。因为,两者的hashCode相同并不能推出他们的内容相同!这是一个原则问题。
比如 A.hashCode() == B.hashCode(),但是,A.equals(B) == false ,那么放入HashMap中时就会发生冲突。比如用拉链法,则A 和 B将会映射到同一个链表中。但是,匹配的时候,C.hashCode() 和A、B的相等,C的内容和B相等,那么最后匹配上的就是B,而不会是A!