hashSet

                        hashSet

实现Set接口的hash table(哈希表),依靠HashMap来实现的。
HashSet实现了Set接口,所以它不能有重复的元素。
我们应该为要存放到散列表的各个对象定义hashCode()和equals()。

先来看一个简单的例子:

 

代码
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetTest {
public static void main(String[] args) {
Set set
= new HashSet(); // 定义一个变量,实例化对象。
set.add("1");//存放元素
set.add("2");
set.add(
"3");
set.add(
"1");// 存放重复的元素
Iterator it = set.iterator();// HashSet中并没有get()方法。这就需要迭代器了。
while (it.hasNext()) {
System.out.println(it.next());
// 打印set中的元素。
}
}
}

输出:

 

3

2

1

虽然加了4个元素,但是打印只有3个元素。这是因为HashSet实现了Set接口,不能有重复的元素。它是怎么样来实现的呢?这是因为我们加入的对象都是String类型的,而String 类重新实现了hashCode()和equals()方法,因此它能对加入的对象进行判断。

hashCode
public int hashCode()
返回此字符串的哈希码。String 对象的哈希码根据以下公式计算:
 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希值为 0。)
覆盖:
类Object中的 hashCode()
equals
public boolean equals(Object anObject)
将此字符串与指定的对象比较。当且仅当该参数不为 null,并且是与此对象表示相同字符序列的 String 对象时,结果才为 true。
覆盖:
类 Object 中的 equals
参数:
anObject - 与此 String 进行比较的对象。
返回:
如果给定对象表示的 String 与此 String 相等,则返回 true;否则返回 false。

 

那么对于我们自己写的类应该为要存放到散列表的各个对象定义hashCode()和equals()。

 

代码
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetTest {
public static void main(String[] args) {
Set set
= new HashSet(); // 定义一个变量,实例化对象。

set.add(
new Student(1, "zhangsan"));
set.add(
new Student(2, "lisi"));
set.add(
new Student(3, "wangwu"));
set.add(
new Student(1, "zhangsan"));// 作为第三者的我们认为加入的是重复的元素
Iterator it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
// 打印set中的元素。
}
}
}

class Student {// 自定义的类,并没有实现hashCode方法和equals方法
private int age;
private String name;

public Student(int age, String name) {
super();
this.age = age;
this.name = name;
}

@Override
public String toString() {
return age + ":" + name;
}
}

 

运行结果:
2
:lisi
1:zhangsan
3:wangwu
1:zhangsan

 

我们认为那是两个重复的元素,但是HashSet却认为这是两个不同的对象,主要是因为HashSet在存储元素的时候,它要根据对象的散列码来计算它的存储位置,而这个散列码是利用Object类当中的hashCode()函数来完成的,而hashCode()是根据对象的内存地址来得到一个散列码,不同的对象当然就有不同的散列码。也就是说我们比较这两个对象仅仅只从它们的age和name来比较的,然而呢,它们是不是同一个对象它们自己知道,自己知道该用什么来比,作为程序员的我们还没能帮忙,反而以为自己帮了忙,我们不能因为张三和张四年龄相同,性格相同,和外貌特征相同就说他们是一个妈生的孩子,要判断他们是不是一个妈生的孩子就得去检查他们的根本(DNA)是否和他们之中某一个人的父亲的DNA相同。所以我们应该为要存放到散列表的各个对象定义hashCode()和equals()。这样我们才能算是真正的帮了忙。

 

 

加入hashCode和equals
class Student {
private int age;
private String name;

public Student(int age, String name) {
super();
this.age = age;
this.name = name;
}

public int hashCode() {
// 如果age能唯一标识一个学生对象,那么就可以直接返回age。
// return age;

// 如果age不能唯一标识一个学生对象,就用age*name
return age * name.hashCode();// age * name.hashCode()作为学生对象的散列码。
// 一个String类型它本身覆盖了基类的hashCode方法,它会根据自己的一个计算规则,计算出自己的散列码。
}

public boolean equals(Object o) {
Student s
= (Student) o;
return age == s.age && name.equals(s.name);

}

@Override
public String toString() {
return age + ":" + name;
}
}

 

运行结果:
1:zhangsan
3:wangwu
2
:lisi

posted @ 2010-12-23 09:17  meng72ndsc  阅读(589)  评论(0编辑  收藏  举报