现在的位置: 首页 > 综合 > 正文

java hashcode和equal总结

2014年03月13日 ⁄ 综合 ⁄ 共 4683字 ⁄ 字号 评论关闭

hashCode和equal两个方法都是Object基类定义实现的方法。hashCode即哈希码,就是获取对象对应的hash值的函数;equal即相等,就是判断两个对象是否相等的函数。为什么Object对象会有这两个方法呢,equal方法好理解,用来比较两个对象是否相等,但是hashCode有什么用呢?

先看下面一段代码,Person类没有重写这两个方法,继承了Object类的方法,我们来看看Object类中定义的这两个方法是如何实现的。

package com.basic.equal;

public class BasicEqual {
	public static void main(String argv[]) {
		Person p1 = new Person("lee", "changsha","123");
		Person p2 = new Person("lee", "changsha","123");
		
		System.out.println(p1 + " " + p1.hashCode());
		System.out.println(p2 + " " + p2.hashCode());
		
		System.out.println(p1.equals(p2));
	}
}

class Person {
	private String name;
	private String address;
	private String number;
	
	public Person(String name, String address, String number) {
		this.address = address;
		this.name = name;
		this.number = number;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
}

运行结果如下:

com.basic.equal.Person@3ce53108 1021653256
com.basic.equal.Person@6af62373 1794515827
false

从上面的结果我们可以看出,Object类的HashCode方法其实返回的就是对象的地址,而equal方法不是很清楚,但通过Object类的源码我们知道equal方法比较的是两个对象的地址。

下面,我们再看一段代码,Person类没有重写这两个方法,继承了Object类的方法

package com.basic.equal;

import java.util.HashSet;
import java.util.Iterator;

public class BasicEqual {
	public static void main(String argv[]) {
		Person p1 = new Person("lee", "changsha","123");
		Person p2 = new Person("lee", "changsha","123");
		
		HashSet<Person> set = new HashSet<Person>();
		set.add(p1);
		set.add(p2);
		
		Iterator<Person> it= set.iterator();
        while(it.hasNext())
        {
        	Person p = it.next();
        	System.out.println(p + " " + p.getName());
        } 
 	}
}

class Person {
	private String name;
	private String address;
	private String number;
	
	public Person(String name, String address, String number) {
		this.address = address;
		this.name = name;
		this.number = number;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
}

运行结果如下:

com.basic.equal.Person@6af62373 lee
com.basic.equal.Person@3ce53108 lee

Hashset不是说保证添加的对象不重复吗,我们构造的对象明明有相同的名字,地址和电话,为什么HashSet认为p1和p2是不同的对象呢,这个就和HashSet判断对象是否相等的方法相关了,HashSet比较两个对象是否相等的,有两个步骤,1)比较HashCode、2)比较equal。下面我们来验证一下是否是这样的,基于下面的代码:

package com.basic.equal;

import java.util.HashSet;
import java.util.Iterator;

public class BasicEqual {
    public static void main(String argv[]) {
        Person p1 = new Person("lee", "changsha","123");
        Person p2 = new Person("lee", "changsha","123");
        
        HashSet<Person> set = new HashSet<Person>();
        set.add(p1);
        set.add(p2);
        
        Iterator<Person> it= set.iterator();
        while(it.hasNext())
        {
            Person p = it.next();
            System.out.println(p + " " + p.hashCode() + " " +p.getName());
        } 
     }
}

class Person {
    private String name;
    private String address;
    private String number;
    
    public Person(String name, String address, String number) {
        this.address = address;
        this.name = name;
        this.number = number;
    }
    
    @Override
    public int hashCode() {
        return 1;
    }
    
    @Override
    public boolean equals(Object obj) {
        return true;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
}

上面代码的运行结果:

com.basic.equal.Person@1 1 lee

我们发现只有一条记录,也就是说hashset认为两个对象是同一个对象,那是因为hashcode值相等了,equal方法返回true了。如果我们让hashcode方法继承object,或者让equal方法继承Object,得到的结果如下:

com.basic.equal.Person@1 1 lee

com.basic.equal.Person@1 1 lee

从上面的试验我们验证了Hashset比较对象的两个方法。通过上面的例子,我们可以看到,其实HashCode方法我们可以不关心直接让它返回固定值,我们只需要实现我们的equal方法就行了,那HashCode方法是不是就没有用了呢,其实它的作用还是很大的,它的作用就是用来提高效率的,我们之所以选择Hahset或hashmap数据结构就是因为它们的效率,比较对象时先通过hashcode缩小范围,然后再使用equal方法比较是否相等,如果我们都是一个hashcode值,相当于比较一个对象时,就需要和所有的对象使用equal方法比较,这样效率就非常的低。我想现在应该差不多明白这两者之间的关系了,^_^。

另外附加hashcode和equals的标准写法:

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime * result + ((number == null) ? 0 : number.hashCode());
		return result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if(getClass() != obj.getClass()) {
			return false;
		}
		Person p = (Person)obj;
		
		if (name == null) {
			if(p.name != null) {
				return false;
			}
		} else if (!name.equals(p.name)) {
			return false;
		}
		
		if (address == null) {
			if (p.address != null) {
				return false;
			}
		} else if (!address.equals(p.address)) {
			return false;
		}
		
		if (number == null) {
			if (p.number != null) {
				return false;
			}
		} else if (!number.equals(p.number)) {
			return false;
		}
		
		return true;
	}

抱歉!评论已关闭.