hashcode()和equals()方法

今天做东西的时候要比较两个实力对象相等问题,所以想到整理一下。之前也有用到,不过没有经常用,都忘了。

在java中,每个对象都继承与object类,它使用equals(),hashcode()方法来判定对象是否相等。

equals()方法在OBJECT中的定义如下:

public boolean equals(object obj){

return (this == obj);
}

很明显,这是两个对象的地址值进行得比较。但是一般情况下,我们想要达到的效果是两个两个对象的内容是否相等。

为了达到这个目的我们就需要重写equals()函数。

public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (address == null) {
			if (other.address != null)
				return false;
		} else if (!address.equals(other.address))
			return false;
		if (description == null) {
			if (other.description != null)
				return false;
		} else if (!description.equals(other.description))
			return false;
		if (id != other.id)
			return false;
		if (identityNo == null) {
			if (other.identityNo != null)
				return false;
		} else if (!identityNo.equals(other.identityNo))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		
		return true;
	}

这里重写equals()方法需要蛮子几个条件:

1) 自反性:对于任何非空应用x,x.equals(x)应该返回true.

2) 对称性:对于任何引用x和y,当且仅当y.equals(x)返回true,x.equals(y)也应该返回true.

3) 传递性:对于任何引用x、y、z,如果x.qeuals(y)返回true,y.equals(z)返回true,x.equals(z)也应该返回true.

4) 一致性:如果x和y引用的对象没有发生变化,反复调用x.equals(y)应该返回同样的结果。

5) 对于任意非空引用x,x.equals(null)应该返回false


对于编写一个完美的equals()有如下建议:

(1)显式参数名othereObject稍后需要转换为一个叫other的比纳凉;

(2)检检测therObject和this是否引用同意对象

      if(this == otherObject )  return true;

 (3)检测otherObject是否为null,如果为null,反悔false

     if(otherObject == null)  return false;

(4)检测this和otherObject是否属于同一类,

          如果equals的语义在每一个子类中有所改变,就使用getClass检测。

             if(getClass() != otherObject.getClass() ) return false;

            如果所有的子类都拥有统一的语义,就使用instanceof检测:

           if(!(otherObject instanceof ClassName)) return false;

(5)将otherObject转换为相应的类类型变量:

          ClassName other = (ClassName) otherObject;

(6)使用 ==比较基本类型域,用equals比较对象域。如果所有的域都匹配,就返回true.否则返回false;

          如果在子类中重新定义equals,就要在其中包含调用super.equals(other)

  

hashcode()

hashCode()方法被用来获取给定对象的唯一整数。这个整数被用来确定对象被存储在HashTable类似的结构中的位置。默认的,Object类的hashCode()方法返回这个对象存储的内存地址的编号。

其必须遵循的约定是: 
1 如果对象equals, 则hashCode一定相等; 
2 如果equals()返回false,这两个对象的hashCode()可能相同。但不等的两个对象返回不同的int值可以提高hashtables的运行效率。 
  作为常理,不相等的对象的hasCode()应可能地返回不同的int值。


重写hashCode()时最重要的原因就是:无论何时,对同一个对象调用hashCode()都应该生成同样的值。如果在将一个对象用put()方法添 加进HashMap时产生一个hashCode()值,而用get()取出时却产生了另外一个 hashCode()值,那么就无法重新取得该对象了。所以,如果你的hashCode()方法依赖于对象中易变的数据,那用户就要小心了,因为此数据发 生变化时,hashCode()就会产生一个不同的hash码,相当于产生了一个不同的“键”。 

      Object的hashCode()方法,返回的是当前对象的内存地址。下次如果我们需要取一个一样的“键”对应的键值对的时候,我们就无法得到一样的 hashCode值了。因为我们后来创建的“键”对象已经不是存入HashMap中的那个内存地址的对象了。 


package com.fit;  
  
import java.util.HashMap;  
  
/** 
 * 身份证类 
 *  
 * @author ZYD 
 *  
 */  
public class Code {  
  
    /** 
     * 身份证号码,一旦确定就不能更改 
     */  
    private final int id;  
  
    public int getId() {  
        return id;  
    }  
  
    /** 
     * 通过构造方法确定身份证号码 
     *  
     * @param id 
     */  
    public Code(int id) {  
        this.id = id;  
    }  
  
    /** 
     * 重写equals()方法 
     */  
    public boolean equals(Object o) {  
        // 如果地址一样,则两个对象相同  
        if (this == o) {  
            return true;  
        }  
        // 如果两个对象是同一类型,则比较其属性值是否都相同。如果都相同,则说明两个对象也相同;否则,说明这两个对象不相同。  
        if (o instanceof Code) {  
            Code co = (Code) o;  
            boolean b = (co.id == this.id);  
            return b;  
        }  
        return false;  
    }  
  
    /** 
     * 重写toString()方法 
     */  
    public String toString() {  
        return "【身份证】:" + id;  
    }  
      
    /** 
     * 测试 
     * @param args 
     */  
    public static void main(String[] args) {  
          
         HashMap<Code, Person> map = new HashMap<Code, Person>();  
           
         Person p1 = new Person(new Code(10001),"张三");  
         Person p2 = new Person(new Code(10002),"李四");  
           
         map.put(p1.getCode(), p1);  
         map.put(p2.getCode(), p2);  
           
         System.out.println("HashMap 中存放的人员信息:\n"+map);  
           
         //张三改名为张山,身份证号不变。  
         Person p3 = new Person(new Code(10001),"张山");  
         map.put(p3.getCode(), p3);  
           
         System.out.println("张三改名为张山后 HashMap 中存放的人员信息:\n"+map);  
           
         //查找身份证为10001 的人员信息  
         System.out.println("查找身份证为:10001 的人员信息:"+map.get(new Code(10001)));  
    }  
}  
  
/** 
 * 人类 
 * @author Administrator 
 * 
 */  
class Person {  
  
    /** 
     * 每一个成人都有一个身份证 
     */  
    private Code code;  
  
    /** 
     * 姓名 
     */  
    private String name;  
  
    public Code getCode() {  
        return code;  
    }  
  
    public void setCode(Code code) {  
        this.code = code;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Person() {  
  
    }  
  
    public Person(Code code, String name) {  
        this.code = code;  
        this.name = name;  
    }  
  
    /** 
     * 重写equals()方法 当两个人得身份证号相同以及姓名相同时,表示这两个人是同一个人。 
     */  
    public boolean equals(Object o) {  
        if (o == this) {  
            return true;  
        }  
        if (o instanceof Person) {  
            Person p = (Person) o;  
            boolean b = this.code.equals(p.code) && this.name.equals(p.name);  
            return b;  
        }  
        return false;  
    }  
  
    /** 
     * 重写toString()方法 
     */  
    public String toString() {  
        return "【姓名】:" + name + "  ";  
    }  
}  

运行结果:

 

HashMap 中存放的人员信息:
{【身份证】:10002=【姓名】:李四  , 【身份证】:10001=【姓名】:张三  }
张三改名为张山后 HashMap 中存放的人员信息:
{【身份证】:10002=【姓名】:李四  , 【身份证】:10001=【姓名】:张三  , 【身份证】:10001=【姓名】:张山  }
查找身份证为:10001 的人员信息:null

 

从上面的结果可以看出:

我们所做的更新和查找操作都失败了。失败的原因就是我们的身份证类: Code 没有覆写 hashCode() 方法。这个时候,当查找一样的身份证号码的键值对的时候,使用的是默认的对象的内存地址来进行定位。这样,后面的所有的身份证号对象

new Code(10001) 产生的 hashCode () 值都是不一样的,所以导致操作失败。

 

 

 重写Code类的hashcode(),代码上:

package com.fit;  
  
import java.util.HashMap;  
  
/** 
 * 身份证类 
 *  
 * @author ZYD 
 *  
 */  
public class Code {  
  
    /** 
     * 身份证号码,一旦确定就不能更改 
     */  
    private final int id;  
  
    public int getId() {  
        return id;  
    }  
  
    /** 
     * 通过构造方法确定身份证号码 
     *  
     * @param id 
     */  
    public Code(int id) {  
        this.id = id;  
    }  
  
    /** 
     * 重写equals()方法 
     */  
    public boolean equals(Object o) {  
        // 如果地址一样,则两个对象相同  
        if (this == o) {  
            return true;  
        }  
        // 如果两个对象是同一类型,则比较其属性值是否都相同。如果都相同,则说明两个对象也相同;否则,说明这两个对象不相同。  
        if (o instanceof Code) {  
            Code co = (Code) o;  
            boolean b = (co.id == this.id);  
            return b;  
        }  
        return false;  
    }  
  
    /** 
     * 重写hashcode()方法,以身份证号码作为hash码。 
     *  
     * @return 
     */  
    public int hashCode() {  
        return id;  
    }  
  
    /** 
     * 重写toString()方法 
     */  
    public String toString() {  
        return "【身份证】:" + id;  
    }  
      
    /** 
     * 测试 
     * @param args 
     */  
    public static void main(String[] args) {  
          
         HashMap<Code, Person> map = new HashMap<Code, Person>();  
           
         Person p1 = new Person(new Code(10001),"张三");  
         Person p2 = new Person(new Code(10002),"李四");  
           
         map.put(p1.getCode(), p1);  
         map.put(p2.getCode(), p2);  
           
         System.out.println("HashMap 中存放的人员信息:\n"+map);  
           
         //张三改名为张山,身份证号不变。  
         Person p3 = new Person(new Code(10001),"张山");  
         map.put(p3.getCode(), p3);  
           
         System.out.println("张三改名为张山后 HashMap 中存放的人员信息:\n"+map);  
           
         //查找身份证为10001 的人员信息  
         System.out.println("查找身份证为:10001 的人员信息:"+map.get(new Code(10001)));  
    }  
}  
  
/** 
 * 人类 
 * @author Administrator 
 * 
 */  
class Person {  
  
    /** 
     * 每一个成人都有一个身份证 
     */  
    private Code code;  
  
    /** 
     * 姓名 
     */  
    private String name;  
  
    public Code getCode() {  
        return code;  
    }  
  
    public void setCode(Code code) {  
        this.code = code;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Person() {  
  
    }  
  
    public Person(Code code, String name) {  
        this.code = code;  
        this.name = name;  
    }  
  
    /** 
     * 重写equals()方法 当两个人得身份证号相同以及姓名相同时,表示这两个人是同一个人。 
     */  
    public boolean equals(Object o) {  
        if (o == this) {  
            return true;  
        }  
        if (o instanceof Person) {  
            Person p = (Person) o;  
            boolean b = this.code.equals(p.code) && this.name.equals(p.name);  
            return b;  
        }  
        return false;  
    }  
  
    /** 
     * 重写toString()方法 
     */  
    public String toString() {  
        return "【姓名】:" + name + "  ";  
    }  
}  

运行效果:

 

HashMap 中存放的人员信息:
{【身份证】:10001=【姓名】:张三  , 【身份证】:10002=【姓名】:李四  }
张三改名为张山后 HashMap 中存放的人员信息:
{【身份证】:10001=【姓名】:张山  , 【身份证】:10002=【姓名】:李四  }
查找身份证为:10001 的人员信息:【姓名】:张山 

如果使用eclipse之类的IDE的话有提供很好的生成equals(0和hashcode()


public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime * result
				+ ((description == null) ? 0 : description.hashCode());
		result = prime * result + id;
		result = prime * result
				+ ((identityNo == null) ? 0 : identityNo.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result
				+ ((password == null) ? 0 : password.hashCode());
		result = prime * result + ((phone == null) ? 0 : phone.hashCode());
		result = prime * result
				+ ((productId == null) ? 0 : productId.hashCode());
		result = prime * result
				+ ((productName == null) ? 0 : productName.hashCode());
		result = prime * result + sign;
		result = prime * result
				+ ((username == null) ? 0 : username.hashCode());
		return result;
	}


  • 两者必须同时重写。
当使用ORM的时候特别要注意的
  • 如果你使用ORM处理一些对象的话,你要确保在hashCode()和equals()对象中使用getter和setter而不是直接引用成员变量。因为在ORM中有的时候成员变量会被延时加载,这些变量只有当getter方法被调用的时候才真正可用。
  • 例如在我们的例子中,如果我们使用e1.id == e2.id则可能会出现这个问题,但是我们使用e1.getId() == e2.getId()就不会出现这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值