一、Object类的equals方法和hashCode方法:
在Object类中equals方法与“==”作用一样,都是比较两个对象的地址。
java code:
public boolean equals(Object obj) {
return (this == obj);
}
在object类中hashCode方法是一个本地方法其定义是:
public native int hashCode();
它的实现是跟本地机器相关的,运用散列算法得到的一个值。为了理解,把它看成对象的内存地址也是可以的。事实上它也参与了Object类的toString()方法的实现:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
toString()的实现是在hashCode()的基础上做了处理。我们一般把Object类的toString()返回的值当成对象的地址,所以我们认为hashCode()与地址拥有一样的特性。
二、子类equals() 和hashCode()的重写:
过去我一直不知道在我们自定义类中重写equals()类的同时要重写hashCode(),不知道hashCode()对于对象的意义。直到做了这么一个实验:
HashSet set = new HashSet();
String A = new String("1");
String B = new String("2");
String C = new String("1");
set.add(A);
set.add(B);
set.add(C);
System.out.println(set.size());
程序得出的结果是 2
set集合中添加三个元素现在只有两个元素。对于A和C来说引用并不相同,而且set的定义是存储对象的引用。既然引用不重复那为什么只有两个元素?
原来set结构存储元不仅是无序和不重复那么简单。set它其实是个map结构。它执行添加也就是add()方法时,首先调用对象的hashCode(),根据返回的值直接去存储到相应的位置。若对应位置上没有元素,直接存储。如果对应的位置上有元素,意味着set存了与该元素有相同的haseCode值的对象。这时会调用对象的equals方法来比较这两个元素,如果equals方法也返回true。那么认为这两个元素是重复的,就不存储了。如果equals方法返回的是false,那么还是会把该元素存进去,散列到其他地址。
然后再来分析上面的结果,String类重写了equals方法和hashcode方法,当元素A存进set后再存C的时候,会调用c的hashcode()方法把C存到指定的位置上,这时发现A已经占到了C的位置,就是说A和C有相同的haseCode的值。因为String类重写了这两个方法。只要equals返回的是true也就是值相等那么hashcode的也一定会相等。这就是为什么A和C的hashcode会相同原因。当发现A和C的hashcode值相同时,再用equals方法比较这两个元素。毫无疑问,A和C用都是String,equals方法返回的是true。那么这时会认为A与C是重复的元素。不会去存储C。这就是为什么A和C只存了A的原因。
现在反过头来看equals和hashcode方法的重写问题。如果我们自定义的类只重写equals方法,只要值相等我们就返回true。不重写hashcode方法。然后我们存两个值相同的对象到set集合。这时就可以存进去重复的元素。
总之我们定义的类要遵循:equals返回true那么hashcode必须相同,hashcode相同equals不一定返回true。
菜鸟不才,抓头皮有感。