经常会碰到一些==跟equals()方法的误用的例子,有时候自己也说不准就弄混了,特地查了些资料写个小小的总结;
首先大致声明一下默认的情况Object的==操作跟equals()是等效的;有些同志会说我错了,会说==操作是比较是否同
一对象的,equals()是比较两个对象内容是否相等的;这样的说法可以说对了一小半,错了一大半;
首先我们来看下Object对象的equals()方法是怎么实现的:
public boolean equals(Object obj) {
return (this == obj);
}
如何?这里已经很明显的告诉大家Object的==操作跟equals()是等效的吧.那有朋友就会问那怎么实现让equals()跟==操作不一样呢?
怎么让equals()方法比较两个对象的内容呢?
答案就是重写equals()方法;下面需要提到重写equals()方法要注意的几点规范:
自反reflexive: x.equals(x)
对称symmetric: x.equals(y)=>y.equals(x)
传递transitive: x.equals(y),<code>y.equals(z) =>x.equals(z)
稳定consistent: x.equals(y) 每次调用的时候总是确定的返回true or false
非空 x.equals(null) return false
从属于==操作 x==y=> x.equals(y) return true
还有非常重要的一点:改写equals()方法后,必须也要改写hashCode()方法; x.equals(y) => x.hashCode()==y.hashCode();
上面解释了一堆关于重写equals()方法的原则,现在我们就倒过头来看看一些已经重写了equals()方法的具体的例子;首先拿String类型来考察
//*************override equals()****************************
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
//*************override hashCode()****************************
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
String类型通过重写了equals(),hashCode()方法实现了String对象的内容比较;基本类型的对象型比如Integer,Long,Float等类型都
实现了自己的equals()方法;正因为基本类型都实现了对象的内容比较,所以经常给我们一种想当然的equals()是比较对象内容的错误观点.
如果我们自己写的类要实现内容比较我们就需要自己重写equals()跟hashCode()方法,关于hashCode()的重写建议参考下String的处理方式,
要尽量避免内容不相等的对象产生相同的hashCode()的错误,否则就会在hashTable中碰到散列值重复的问题,这个按下不表.
最后额外的讲一下String的==的问题.经常碰到别人问String str="abc";String str2=new String("abc") String str3="abc"中有几个对象的无聊问题.
这里我给出我自己的解释共str,str2,str3,"abc", new String("abc")五个对象.其中str,str2,str3是reference对象存于JVM的STACK中,"abc"是一个内存对象容纳
了"abc"这个数据,存在于JVM的String池中(str,str3指向的"abc"是同一内存区--String池中的"abc"),new String("abc")是一个内存对象容纳了"abc"这个数据,存在
于JVM的Heap 堆中;
按照上面的解释我们可以明确知道str != str2,因为他们在内存中是两个对象(一个在STRING池中一个在HEAP堆中), str == str3因为他们指向的是String池中的同一对象;
我们通过str="abc";str3="abc"实例化时,JVM会检查String池中是否已经存在"abc"对象,如果有那么就把引用指向已经存在的"abc";否则就在String池中新建立一个.
我们通过str2=new String("abc")实例化时,首先这里分配的内存跟STRING池是没有任何关系的,无论HEAP堆和STRING池中有无"abc" JVM都会在HEAP堆里新建立一个
"abc"对象;
OK,打完收工,算是整理下自己的思路,来个小小结:)