在往HashSet集合中放数据的时候,由于HashSet底层是用HashMap中的Key属性存储的,所以是不能重复的,那他如何判断其不是重复的元素呢.这个时候他判断有两步.
1.调用元素的hashcode 方法,判断两对象的hashCode 是否相等,如果不相等,则认为两对象不相等,结束.如果相等,则转入equals 方法进行判断.
2.如果equals 方法返回true则,是相等的.如果返回false则是不相等的.结束.这里是最终结果.
总的归纳是如果在调用hashCode 方法时判断了对象不相等那就有了结论.不用调用equals 方法了
如要以上推论成立,需要验证四个结论:
1.这个hashCode 方法中返回的结果是永远也不相等的,因此会调用equals 方法进行判断,结果是所有元素都打印出来了.
2.hashCode 方法不变,修改equals 方法,让其总返回false,结果和1一样.
---->以上两点成立的话,说明hashCode 方法返回的值不相等的话,结果就与equals 方法无关了.
3.当把hashCode 方法中返回数改成一常量时,equas方法总return false,结果是返回第一个元素;
4.当把hashCode 方法中返回数改成一常量时,equas方法总return ture 结果返回全部元素.
----->以上两点成立的话,说明hashCode 方法返回的值相等的话,结果有equals 方法控制.
import java.util.HashSet;
import java.util.Iterator;
public class TestHashSet {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet hs = new HashSet();
String a="123";
hs.add(new Element(a,"mengchao"));
hs.add(new Element(a,"mengchao"));
hs.add(new Element("1234","mengchao3"));
Iterator it=hs.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
class Element{
private String num;
private String name;
static int i=0;
public Element(String num,String name){
this.num=num;
this.name=name;
}
public String toString(){
return "学号为:"+num+";————名字为"+name;
}
public int hashCode(){
return i++;
}
public boolean equals(Object o){
Element os = (Element)o;
return true;
}
}
结果:
学号为:1234;————名字为mengchao3
学号为:123;————名字为mengchao
学号为:123;————名字为mengchao
将equals 方法中 return true; 改成 return false;结果还是一样.
import java.util.HashSet;
import java.util.Iterator;
public class TestHashSet {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet hs = new HashSet();
String a="123";
hs.add(new Element(a,"mengchao"));
hs.add(new Element(a,"mengchao"));
hs.add(new Element("1234","mengchao3"));
Iterator it=hs.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
class Element{
private String num;
private String name;
//static int i=0;
public Element(String num,String name){
this.num=num;
this.name=name;
}
public String toString(){
return "学号为:"+num+";————名字为"+name;
}
public int hashCode(){
return 3;
}
public boolean equals(Object o){
Element os = (Element)o;
return true;
}
}
运行结果:
学号为:123;————名字为mengchao
将equals 方法中 return true; 改成 return false;
运行结果:
学号为:1234;————名字为mengchao3
学号为:123;————名字为mengchao
学号为:123;————名字为mengchao
在Object类中定义的几个hashCode约定如下:
1. 在同一应用中,一个对象的hashCode函数在equals函数没有更改的情况下,无论调用多少次,它都必须返回同一个整数。
2. 两个对象如果调用equals函数是相等的话,那么调用hashCode函数一定会返回相同的整数。
3. 两个对象如果调用equals函数是不相等的话,那么调用hashCode函数不要求一定返回不同的整数。
补充一点我自己的看法,拿HashMap来举例,
在HashMap中保存元素的值是一个 transient Entry[] table,也就是一个数组。在这里要特别注意Entry的元素,在Entry中它有一个属性next,记录了和本节点具有相同的Hash码的对象。但是它们的Equals方法返回的是false。这也解释了为什么先去判断HashCode值,还要再去判断equals方法了。
在往HashMap中加入数据的过程是这样的,首先要根据key的hashcode值,根据一定的散列算法,找到对应table上的位置,如果该位置已经有value存在了,那么,判断旧value的key和新插入值的key的equals方法是否相等,如果相等,把旧value替换成新插入值。key不变(因为hashcode和equals都相等,HashMap就认为这两个key是相等的)。如果不相等,则将旧value的entry的next属性设置为新value对应的entry属性(实际上这就是解决hash冲突的一种方法)。
从HashMap中取出元素的过程和上面刚好相反,在这里就不叙述了。