参考:http://blog.youkuaiyun.com/hzw19920329/article/details/51944114
1、equals和==
equals的作用是用来判断两个对象是否相等,Java中所有的类都实现了equals方法。在equals没有被重写的情况下equals等价于==
==比较(这里指对象比较)的是两个对象是否是同一个对象
public class User {
private String username;
private String pass;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public User(String username, String pass) {
super();
this.username = username;
this.pass = pass;
}
}
用==测试
public static void main(String[] args) {
User u1=new User("vivien","1234");
User u2=new User("vivien","1234");
System.out.println(u1==u2);
System.out.println(u1.equals(u2));
}
输出
false
false
尽管变量都一样,但是这两个毕竟不是同一个对象,所以执行==时显示false,而在没有重写equals的时候equals等价于==(String默认是重写了equals的,所以执行equals的时候new两个一样的String用equals比较是true)
重写equals:
public class User {
private String username;
private String pass;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public User(String username, String pass) {
super();
this.username = username;
this.pass = pass;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj==null)
return false;
if(obj==this)
return true;
if(obj instanceof User)
{
User o=(User)obj;
if(o.getUsername()==this.username && o.getPass()==this.pass)
return true;
else return false;
}
else
{
return false;
}
}
}
重新测试显示:
false
true
可以发现重写了equals之后输出true
注意equals原则:
1. 对称性:如果x.equals(y)返回是”true”,那么y.equals(x)也应该返回是”true”。
2. 反射性:x.equals(x)必须返回是”true”。
3. 类推性:如果x.equals(y)返回是”true”,而且y.equals(z)返回是”true”,那么z.equals(x)也应该返回是”true”。
4. 一致性:如果x.equals(y)返回是”true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是”true”。
5. 非空性,x.equals(null),永远返回是”false”;x.equals(和x不同类型的对象)永远返回是”false”。
2、equals和hashCode()
hashCode()的作用是获取哈希码,也称为散列码,返回的是一个int整数。
这两个如果不是在散列表中比较完全没有意思。因为如果这个类不是放在散列表中,equals和hashCode()没有半毛钱关系。
这里我以hashMap来说两者关系吧
HashMap解决冲突的方法时拉链法(把所有hashCode相同的键值对用单链表连接起来),这也导致了HahMap的结构–数组+链表:
每个键值对在hashMap中是以Entry的形式存在
HashMap的put原理:
首先用hashCode()方法计算当前key的hash值,接着找到计算出来的hash值在数组中的下标位置,查看该下标位置处对应的链表是否为null,为null的话直接将当前键值对插入到该链表首位。如果下标位置处对应的链表不为null的话,会使用for循环,每次循环通过key的equals()方法查看这个链表中有没有与当前键值对相等的Entry存在,有的话会用当前值替换原先这个键值对的value值,遍历结束如果不存在的话,会将当前键值对插入到链表头部。
HashMap的get原理
get操作过程思想可以借助于put过程,首先会计算出当前key值的hash值,接着找到此hash值在数组中的位置,找到这个位置对应的链表,接着通过for循环遍历这个链表,遍历过程中调用equals方法查看有没有等于当前key的键值对存在,有的话直接返回这个键值对对应的value值即可
所以HashMap 如果想要实现让对象做key,并且相同变量的对象视为相同的key的话,一定要重写equals()方法和hashCode()方法。什么意思呢,直接看例子:
上面的User类如果我没有重写equals()方法和hashCode()方法,把User类作为key,存到HashMap中时:
public static void main(String[] args) {
Map<User,String> m=new HashMap<User,String>();
User u1=new User("vivien","1234");
User u2=new User("vivien","1234");
m.put(u1, "这是u1");
m.put(u2, "这是u2");
System.out.println("u1 hashCode():"+u1.hashCode());
System.out.println("u2 hashCode():"+u2.hashCode());
System.out.println("u1.equals(u2)?"+u1.equals(u2));
Set<Map.Entry<User, String>> entries=m.entrySet();
Iterator it=entries.iterator();
while(it.hasNext())
System.out.println(it.next());
}
输出(为了输出直观,为在User中重写了toString()方法):
u1 hashCode():1704856573
u2 hashCode():705927765
u1.equals(u2)?false
User [username=vivien, pass=1234]=这是u1
User [username=vivien, pass=1234]=这是u2
很显然,u1和u2hashCode不一样,并且也不equals,HashMap把u1和u2当做两个key来对待
现在重写equals和hashCode()方法:
public class User {
private String username;
private String pass;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
@Override
public String toString() {
return "User [username=" + username + ", pass=" + pass
+ "]";
}
public User(String username, String pass) {
super();
this.username = username;
this.pass = pass;
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj==null)
return false;
if(obj==this)
return true;
if(obj instanceof User)
{
User o=(User)obj;
if(o.getUsername()==this.username && o.getPass()==this.pass)
return true;
else return false;
}
else
{
return false;
}
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return (this.username+this.pass).hashCode();
}
}
重新运行上面的test:
u1 hashCode():-1331478383
u2 hashCode():-1331478383
u1.equals(u2)?true
User [username=vivien, pass=1234]=这是u2
这时可以看到,在插入u2时,HashMap首先计算u2 hashCode,找到了与u1相同hashCode的链,在这个链中,通过for循环发现u1的key equals u2的key,所以把u2对应的value覆盖u1对应的value。所以最后遍历Map发现只有一个键值对