java对象中equals方法的重写

最近重新研究java基础, 看到了java中Object类的equals()方法。java中比较两个对象相等性有两个方法,一个是==, 另一个是俄quals()方法(当然基本类型不能直接调用,需要包装类包装)。常问的问题就是这两个方法的区别,很多人会说出好几条区别,比如==比的是对象的引用,equals比较的是对象的值。其实这是一种误解,看看Object类中equals()方法的源代码。

public boolean equals(Object obj) {
return (this == obj);
}

就这么简单, 原来equals调用的就是==。那么上述的论断来源于哪儿呢,其实很多人都说得是String类重写的equals方法。

重写equals很简单,以下举一个简单例子来演示一下

class Person{

private String name;
private int age;

public Person(String name, int age){
this.name = name;
this.age = age;
}
// 省略getter/setter方法

}

然后我们就可以来试验equals和==了
Person p1 = new Person("xg", 29);
Person p2 = new Person("xg", 29);
System.out.println(p1 == p2);
System.out.println(p1.equals(p2));

结果都是false,显然。
那么接下来就是要重写equals了。目前流行的写法如下:

public boolean equals(Object obj){

if (obj == null) {
return false;
}else if(!(obj instanceof Person)){
return false;
}
Person p = (Person)obj;
if(this.getName().equals(p.getName()) && this.getAge() == p.getAge()){
return true;
}else{
return false;
}
}

思路很清晰,不说了

不过我更喜欢另一种简单的写法

public boolean equals(Object obj){
if (obj instanceof Person){
return this.getName().equals(((Person)obj).getName())
&& this.getAge() == ((Person)obj).getAge();
}else {
return false;
}
}
这种写法更加简洁,功能是一样的。

再试验上面的例子
Person p1 = new Person("xg", 29);
Person p2 = new Person("xg", 29);
System.out.println(p1 == p2);
System.out.println(p1.equals(p2));
返回false,true,因为equals被重写了。

到此似乎已经很完美了,其实不然,看到下面的结果就会发现。

Map<Person, String> map = new HashMap<Person, String>();
map.put(new Person("xg", 28), "Person1");
System.out.println(map.get(new Person("xg", 28)));

本以为应该返回Person1的字符串,确返回了一个null,这是怎么回事呢?
让我们看看HashMap中get方法是怎么实现的

public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode()); // 获得参数key的hashCode
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) // 比较hashCode,如果相同则返回值
return e.value;
}
return null; // 否则返回null
}

那我们就看一看hashCode吧。

Person p1 = new Person("xg", 29);
Person p2 = new Person("xg", 29);
System.out.println(p1.hashCode() + "----" + p2.hashCode());
我们看到两个完全不同的值

那么好了,根据java的Object规范,当两个对象的equals方法返回true时,这两个对象的hashCode必须返回同样的值。为什么要这么规定呢?相信原因你已经知道了,因为一旦不同,那么这个对象在与HashMap,Hashtable,HashSet一起使用时,一定要有问题。(想象一下如果String类没有重写HashCode那将多么可怕)

那么如何重写hashCode方法呢,这个难度就很大了,目前已知的是,如果能保持不同的对象,返回不同的hashCode值,这就是最好的。原理参见hash算法的实现。

接下来就重写一个

public int hashCode(){
return this.name.length()*37 + this.age;
}

再试验一下例子

Map<Person, String> map = new HashMap<Person, String>();
map.put(new Person("xg", 28), "Person1");
System.out.println(map.get(new Person("xg", 28)));

OK了,结果是Person1。

结论:重写equals一定要重写hashCode。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值