HashSet is a binary tree collection with unique elements, and HashSet is an implementation class of the Set interface (HashSet implements the Set interface), which has the characteristics of Set.
The characteristics of Set are: non-repeatable, elements are out of order, and there is no method with index (so ordinary for loops cannot be used to traverse, nor can the index be used to obtain or delete element values in the Set collection).
The characteristics of HashSet are: the underlying data structure is a hash table; there is no guarantee for the iteration order of the set, that is to say, there is no guarantee that the elements are stored and retrieved in the same order (that is, the elements are out of order); there is no method with an index (so you cannot use ordinary for loop to traverse, nor to obtain or delete the element value in the HashSet collection through the index); it cannot be repeated.
Next we will learn HashSet from the four characteristics of HashSet and combine the code. (Since HashSet does not have an index method, the fourth feature of HashSet can only use forEach statement and Iterator iterator to realize the traversal of HashSet)
注意:同样的,HashSet与TreeSet均是Set接口的一个实现类,因此HashSet的默认数据类型也是Object类,理论上我们可以通过add()方法来添加任意数据类型,但是如果我们这样子做,当我们进行遍历输出的时候就会遇到麻烦!!!因此我们在使用HashSet的时候,请使用泛型来约束数据类型!!!
Since the hash table is also a very important knowledge point, let's skip it here and talk about the last three features of HashSet first. After that, the author will write a knowledge point blog for the hash table separately.
1. Non-repeatable
HashSet of String type
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<String> hashset=new HashSet<>();
//使用add()方法来添加数据
hashset.add("bb");
hashset.add("aa");
hashset.add("cc");
hashset.add("ee");
hashset.add("aaa");
hashset.add("bb");
//打印
System.out.println(hashset);
}
Running results (duplicate bb elements are filtered out)
Second, use the forEach statement and Iterator iterator to traverse the output HashSet
The forEach statement traverses the output HashSet
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<String> hashset=new HashSet<>();
//使用add()方法来添加数据
hashset.add("bb");
hashset.add("aa");
hashset.add("cc");
hashset.add("ee");
hashset.add("aaa");
hashset.add("bb");
//在此我们使用forEach来遍历HashSet
//String是hashset的数据类型,我们将hashset的数据存入str(此名字你可以自定义)中并输出
for(String str:hashset){
System.out.println(str);
}
}
Running results (duplicate bb elements are filtered out)
The Iterator iterator traverses the output HashSet
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<String> hashset=new HashSet<>();
//使用add()方法来添加数据
hashset.add("bb");
hashset.add("aa");
hashset.add("cc");
hashset.add("ee");
hashset.add("aaa");
hashset.add("bb");
//创建迭代器对象,由于hashset的类型是String类型,因此迭代器的数据类型也是String
Iterator<String> iterator=hashset.iterator();
//判断该位置是否有值,iterator.hasNext()它会查看我们当前位置是否存在元素,存在元素返回true,不存在元素返回false
while(iterator.hasNext()){
//获取该位置的元素值,iterator.next()它会取得我们目前位置的元素,然后指针后移
System.out.println(iterator.next());
}
}
Running results (duplicate bb elements are filtered out)
3. The order of storing and fetching elements is not guaranteed to be consistent
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<String> hashset=new HashSet<>();
//使用add()方法来添加数据
hashset.add("zhangsan");
hashset.add("wangwu");
hashset.add("lisi");
hashset.add("aa");
hashset.add("aaa");
hashset.add("aa");
//打印
System.out.println(hashset);
}
Running the results (duplicate aa elements are filtered out), we found that the order of our output is inconsistent with the order of insertion, so HashSet does not guarantee that the order of storing and extracting elements is consistent.
4. Case-HashSet collection stores student objects and traverses
The original Student class
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
HsahSet's main() method
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<Student> hashset=new HashSet<>();
//使用add()方法来添加数据
hashset.add(new Student("zhangsan",18));
hashset.add(new Student("zhangsan",18));
hashset.add(new Student("lisi",18));
hashset.add(new Student("wangwu",20));
hashset.add(new Student("chenliu",20));
//创建迭代器对象,由于hashset的类型是Student类型,因此迭代器的数据类型也是Student
Iterator<Student> iterator=hashset.iterator();
//判断该位置是否有值,iterator.hasNext()它会查看我们当前位置是否存在元素,存在元素返回true,不存在元素返回false
while(iterator.hasNext()){
//获取该位置的元素值,iterator.next()它会取得我们目前位置的元素,然后指针后移
System.out.println(iterator.next());
}
}
In the main() method, we insert two identical objects, and we check whether duplicate values will be screened out.
Running results (we find that both of them are output, and the duplicate values we think are not screened out)
那么这是为什么呢?其实我们在元素进行比较的时候,计算机并不是通过比较他们的对象值来判定他们是否不同,而是通过比较他们存储的内存地址来比较他们是否不同,那么我们接下来分别输出它们的HashCode()的值(对象存储的内存空间的int类型数值)
hashCode's main() method
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<Student> hashset=new HashSet<>();
//创建Student对象
Student s1=new Student("zhangsan",18);
Student s2=new Student("zhangsan",18);
//打印hashcode值,观察他们的内存地址是否相同
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
operation result(We found that the hashCode values of the two of them are different, which is why the computer does not think they are the same)
那么我们如何使得计算机知道他们两个是相同的呢,这就需要我们在Student类中重写HashCode()方法
Improve the Student class
笔者用的编译器是IDEA,在IDEA的Student类中右键--->Generate...
选中equals() and hashCode()
点击Next
点击Next
点击Next
点击Finish
The rewritten Student class
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
hashCode's main() method
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<Student> hashset=new HashSet<>();
//创建Student对象
Student s1=new Student("zhangsan",18);
Student s2=new Student("zhangsan",18);
//打印hashcode值,观察他们的内存地址是否相同
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
The running results are as follows: (we can see that the computer already thinks that s1 and s2 are the same)
Run the following main() method
public static void main(String[] args) {
//若要使用HashSet,我们需要导入import java.util.HashSet;
//我们使用泛型来约束HashSet的数据类型为String数据类型
HashSet<Student> hashset=new HashSet<>();
//创建Student对象
Student s1=new Student("zhangsan",18);
Student s2=new Student("zhangsan",18);
//添加对象
hashset.add(s1);
hashset.add(s1);
//1:普通打印
System.out.println(hashset);
System.out.println("====华丽的分割线====");
//2:forEach打印
for(Student stu:hashset){
System.out.println(stu);
}
System.out.println("====华丽的分割线====");
//3:Iterator迭代器打印
Iterator<Student> iterator=hashset.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
The running results are as follows: (We can see that the computer already thinks that s1 and s2 are the same at this time, and filters out duplicate values)
OK! ! ! Finish! ! !