equals()是判读两个Set是否相等[前提是equals()在类中被覆盖]。==决定引用值是否指向同一对象。
1、当向集合set中增加对象时,首先计算要增加对象的hashCode码,根据该值来得到一个位置来存放当前的对象,当在该位置没有一个对象存在的话,那么集合set认为该对象在集合中不存在,直接增加进去。如果在该位置有一个对象的话,接着将准备增加到集合中的对象与该位置上的对象进行equals方法比较,如果该equals方法返回false,那么集合认为集合中不存在该对象,再进行一次散列,将该对象放到散列后计算出的新地址里,如果equals方法返回true,那么集合认为集合中已经存在该对象了,不会再将该对象增加到集合中了。
2、当重写equals方法时,必须要重写hashCode方法。在java的集合中,判断两个对象是否相等的规则是:
1),判断两个对象的hashCode是否相等
如果不相等,认为两个对象也不相等,完毕 ; 如果相等,转入2
2),判断两个对象用equals运算是否相等
如果不相等,认为两个对象也不相等
如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
可见hashcode()相等时,equals()方法也可能不等。
public static void main(String args[]){
String s1=new String("zhaoxudong"); //此语句创建了两个对象,一个是字符串对象“zhaoxudong”(存放于栈中的字面量),另一个是new后在堆中产生的对象。详细见下面的四.4
String s2=new String("zhaoxudong");
//上述两条语句一共是产生了三个对象,因为栈中只有产生了一个对象。
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode() ,指向同一内存的引用
System.out.println(s2.hashCode()); //equals和hashCode方法只用于两个对象的比较和容器中,与对象的创建没有关系
Set hashset=new HashSet();
hashset.add(s1);
hashset.add(s2); /*在添加s1,s2时, hashset认为s1和s2是相等的,所以让s2覆盖了s1;*/
Iterator it=hashset.iterator();
while(it.hasNext()){
System.out.println(it.next());
} //最后在while循环的时候只打印出了一个”zhaoxudong”。
这是因为String类已经重写了equals()方法和hashcode()方法。
但是看下面的程序:
public class HashSetTest {
public static void main(String[] args) {
HashSet hs=new HashSet();
hs.add(new Student(1,"zhangsan"));
hs.add(new Student(2,"lisi"));
hs.add(new Student(3,"wangwu"));
hs.add(new Student(1,"zhangsan"));
Iterator it=hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
} } }
class Student {
int num;
String name;
Student(int num,String name) {
this.num=num;
this.name=name; }
public String toString() { return num+":"+name; }
}
输出结果为:
1:zhangsan
1:zhangsan
3:wangwu
2:lisi
问题出现了,为什么hashset添加了相等的元素呢,这是不是和hashset的原则违背了呢?回答是:没有因为在根据hashcode()对两次建立的new Student(1,"zhangsan")对象进行比较时,生成的是不同的哈希码值,所以hashset把他当作不同的对象对待了,当然此时的equals()方法返回的值也不等。那么为什么会生成不同的哈希码值呢?原因就在于我们自己写的Student类并没有重新自己的hashcode()和equals()方法,所以在比较时,是继承的object类中的hashcode()方法,它是一个本地方法,比较的是对象的地址(引用地址),使用new方法创建对象,两次生成的当然是不同的对象了,造成的结果就是两个对象的hashcode()返回的值不一样。那么怎么解决这个问题呢??
答案是:在Student类中重新hashcode()和equals()方法。
例如:
class Student{
int num;
String name;
Student(int num,String name){
this.num=num;
this.name=name; }
public int hashCode(){ //重写hashCode的方法
return num*name.hashCode(); }
public boolean equals(Object o) {
Student s=(Student)o;
return num==s.num && name.equals(s.name); //&&的优先级比==低,所以前面不必加括号
}
public String toString(){return num+":"+name; }
}
根据重写的方法,即便两次调用了new Student(1,"zhangsan"),我们在获得对象的哈希码时,根据重写的方法hashcode(),获得的哈希码肯定是一样的。所以运行修改后的程序时,我们会看到重复元素的问题已经消除。
在hibernate的pojo类中,经常使用set集合来保存相关对象,而set集合是不允许重复的。所以需要重写equals和hashCode()方法。
比如可以这样写:
public int hashCode(){
return 1;}//等价于hashcode无效
这样做的效果就是在比较哈希码的时候不能进行判断,因为每个对象返回的哈希码都是1,每次都必须要经过比较equals()方法后才能进行判断是否重复,这当然会引起效率的大大降低。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/elia1208/archive/2009/10/12/4657644.aspx