```java
public class Student {
private int no;
private String name;
public Student() {}
public Student(int no,String name) {
this.no = no;
this.name = name;
}
// 构造方法可以一次赋两个值,这个方法用于单个赋值
/*public void setNo(int no) {
this.no = no;
}
public void setName(String name) {
this.name = name;
}*/
public int getNo() {
return no;
}
public String getName() {
return name;
}
public String toString() {
return "["+no+","+name+"]";
}
public int hashCode() {
return no;
}
// Object的equals方法不适用,所以需要重写equals()方法
public boolean equals(Object object) {
// 这里需要强转,因为重写时需保证与父类参数类型一致,所以重写方法的参数类型也为Object
Student student = (Student)object;
//this.no == no && this.name == name也可
if(no == student.getNo() && name == student.getName()) {
return true;
}
return false;
}
}
```java
import java.util.*;
public class TestSet {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 使用顺序存储结构存储
Set set = new HashSet();
Student s1= new Student(1,"张三");
Student s2 = new Student(2,"李四");
set.add(s1);
set.add(s2);
set.add(new Student(3,"王五"));
set.add(new Student(3,"王五"));
set.add(new Student(2,"李四"));
// 遍历方式,迭代器
// 第一步,通过集合获取迭代器
Iterator it = set.iterator();
// 第二步,通过循环来控制it.next();
while(it.hasNext()) {
// 第三步,通过迭代器获取集合的元素it.next();
Object object = it.next();
System.out.println(object);
}
// 第二种遍历方式:foreach循环遍历
/*for(Object o : set) {
System.out.println(o);
}*/
}
}
- 从程序的入口进来,当我向集合添加前两个元素时,如图所示,对于s1和s我是先创建的对象,然后再尝试把他们加进来,根据debug的调试过程我们可以看到,向集合添加元素时首先会去执行当前对象的hashCode()方法,返回一个hashcode值,并根据这个值,决定此元素的存放位置。第1,2两个元素hashCode值不同,所以两个元素都顺利被加进集合
- set.add(new Student(3,“王五”));而这一行语句的执行状况是先执行Student的构造方法,再返回到当前set.add(new Student(3,“王五”));语句,再去执行Student的hashCode()方法,其他语句类似
- 重点equals()
我们向hashset中添加元素a,首先调用a所在类的hashcode方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在hashset底层数组中的存放(索引位置),判断此位置上是否已经有元素;
如果此位置上没有其他元素,则添加成功–情况1
如果此位置上有其它元素b(或以链表形式存在的多个元素),则比较a和b的hash值:
如果hash值不同,则元素a添加成功–情况2
通过hash值相同,进而需要调用a所在类的equals方法:
equals返回true,a添加失败
equals返回false,a添加成功
- equals的具体执行过程:
- 以上图代码为例,第二个元素与第五个元素相同,在执行第五个元素的添加语句时,此时第二个元素已经在集合中,返回第五个元素的hashCode值时,发现此元素的hashCode值与集合已经存在的元素相同,于是去执行第五个元素的equals方法,我重写的equals方法中if的判断条件是no == student.getNo() && name == student.getName()
注意看此时的this的地址比较大,说明此时this是第五个元素,而Object地址很小,说明集合中已经存在的第二个元素才是被比较的对象,即新.equals(旧)