如果想查找一个集合中是否包含有某个对象,大概的程序代码怎样写呢?你通常是逐一取出每个元素与要查找的对象进行比较,当发现某个元素与要查找的对象进行equals方法比较的结果相等时,则停止继续查找并返回肯定的信息,否则,返回否定的信息。
如果一个集合中有很多个元素,譬如有一万个元素,并且没有包含要查找的对象时,则意味着你的程序需要从该集合中取出一万个元素进行逐一比较才能得到结论,
有人发明了一种哈希算法来提高从集合中查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域根据一个对象的哈希码就可以确定该对象应该存储在哪个区域,如下图所示。
HashSet就是采用哈希算法存取对象的集合,它内部采用对某个数字n进行取余的方式对
哈希吗进行分组和划分对象的存储区域,Object类中定义了一个hashCode()方法来返回每个Java对象的哈希吗,当从HashSet集合中查找某个对象时,Java系统首先调用对象的hashCode()方法获得该对象的哈希吗,然后根据哈希码找到相应的存储区域,最后取出该存储区域内的每个元素与该对象进行equals方法比较,这样不用遍历集合中的所以元素就可以得到结论。可见,HashSet集合具有很好的对象检索性能,但是,HashSet集合存储对象的效率相对要低些,因为向HashSet集合中添加一个对象时,要先计算出对象的哈希码和根据这个哈希码确定对象再集合中的存放位置。
为了保证一个类的实例对象能再HashSet正常存储,要求这个类的两个实例对象用equals()方法比较的结果相等时,它们的哈希码也必须相等。也就是说,如果
Obj1.equals(obj2)的结果为true,那么以下表达式的结果也要为true:
Obj1.hashCode()==obj2.hashCode()
-----------------------------------
哈希表使用哈希值来存的。取也是按哈希值来取的。在哈希表里,如果哈希值重复的话,还有一次校验方式、就是校验两个对象是不是同一个对象(使用equals方法)。
如果哈希值一样,但不是同一对象,不同就放到前一个对象的后面顺延。
如果哈希值不一样就不需要比较是不是同一对象了。
---------------------------------------
HashSet集合就是哈希表结构的。
Set集合的功能和Collection是一致的。而Set集合只有一种取的方式就是迭代器。
class HashSetDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add("java01);
hs.add("java02");
hs.add("java03");
hs.add("java04");
Iterator it = hs.iterator();
while(it.hasNext())
{
sop(it.next());
}
}
}
----------------------------
class HashSetDemo
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();
sop(hs.add("java01"));
sop(hs.add("java01"));
hs.add("java02");
hs.add("java03");
hs.add("java03");
hs.add("java04");
Iterator it = hs.iterator();
while(it.hasNext())
{
sop(it.next());
}
}
}
发现地址是一样的。。添加不成功。。
(String 类重写了hashCode()方法和equals方法,注意:String是final类,常量字符串)
-------------------------集合框架--HashSet存储自定义对象
/*
往hashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。
*/
class HashSetTest
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
hs.add(new Person("a2",12));
Iterator it = hs.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public int hashCode()
{
System.out.println(this.name+"....hashCode");
return 60;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
System.out.println(this.name+"...equals.."+p.name);
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
修改下上面程序的hashCode()如下:
public int hashCode()
{
System.out.println(this.name+"....hashCode");
return name.hashCode()+age;
}
再次运行:
------------------
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的hashcode值不同,不会调用equals。
----------------------
集合框架--HashSet判断和删除
class HashSetTest
{
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
HashSet hs = new HashSet();
hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
// hs.add(new Person("a2",12));
// hs.add(new Person("a4",14));
sop("a1:"+hs.contains(new Person("a2",12)));
// hs.remove(new Person("a4",13));
Iterator it = hs.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
}
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。
ArrayList判断元素是否存在和删除元素只依赖equals。而HashSet判断元素是否存在和添加删除元素时,先依赖hashCode再依赖于equals。
全都依赖在数据结构上,数据结构不同,依赖的方法也不同。
------------------------------------------
提示:
(1)通常来说,一个类的两个实例对象用equals()方法比较的结果相等时,他们的哈希码也必须相等,但反之则不成立,即equals方法比较结果不相等的对象可以有相同的哈希码,或者说哈希码相同的两个对象的equals方法比较的结果可以不等,例如,字符串“BB”和“Aa”的equals方法比较结果肯定不相等,但他们的hashCode方法返回值却相等。
(2)当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。