1、特点
1、HashSet实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。
2、它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
3、Set接口定一个不包含重复元素的 collection,HashSet的元素自然也不能重复
4、只能存储引用类型,JDK1.5后对基本类型有了自动装箱,会将基本类型自动转换为其包装类。
2、add方法分析
boolean add(E e);如果此 set 中尚未包含指定元素,则添加指定元素。
该方法底层分析:
1、首先获取待添加元素的哈希值(e.hashCode();),与集合中的元素的哈希值进行比较。
2、如果集合中不存在与待添加元素哈希值相同的元素,则将待添加的元素,添加到集合中。(哈希值可以理解为一块内存空间,这块内存里面可能存在多个对象,所以理论上可能出现,多个对象的哈希值相同,地址值不同的情况)
3、如果集合中存在与待添加元素哈希值相同的元素,则调用equals()方法比较这两个元素,如果不相同就添加,否则不添加
注意:如果没有重写equals方法,则调用的是Object中的equal()方法,比较这两个元素的地址,如果地址不相同,就将待添加的元素,添加到集合中,否则不添加。
4、所以一般情况下,需要根据具体的要求重写hashCode方法和equals方法。
3、添加String字符串
Java代码
public static void main(String[] args) {
//创建集合对象
HashSet hs=new HashSet();
String str1="hello";
String str2="world";
String str3="java";
String str4="hello";
System.out.println("str1的哈希值:"+str1.hashCode());
System.out.println("str2的哈希值:"+str2.hashCode());
System.out.println("str3的哈希值:"+str3.hashCode());
System.out.println("str4的哈希值:"+str4.hashCode());
hs.add(str1);
hs.add(str2);
hs.add(str3);
hs.add(str4);
System.out.println("====================");
for (String string : hs) {
System.out.println(string);
}
}
运行结果:
str1的哈希值:99162322
str2的哈希值:113318802
str3的哈希值:3254818
str4的哈希值:99162322
====================
world
java
hello
分析:
1、可以看出最后一个hello元素没有进入集合,且集合中的元素顺序和存入的顺序不同。
2、String类重写的hashCode方法,所以获取哈希值,调用的是String类中的hashCode方法
3、上述代码中看到str1和str2、str3的哈希值互不相同,和str4的哈希值相同,
4、集合为空,str1直接添加进入集合,
5、str1、tr2、str3互不相同,所以str2、str3、也添加到集合中,
6、str4与str3的哈希值相同,此时调用String类的equals方法,比较字符串的值,发现相同,不添加str4
4、添加对象
需求:存储自定义对象,并保证元素的唯一性
要求:如果两个对象的成员变量值都相同,则视为同一个元素
学生对象:
package com.xiaowen.demo2;
public class Student {
private String name;
private String age;
public Student() {
}
public Student(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
测试类:
public static void main(String[] args) {
//创建集合对象
HashSet hs=new HashSet();
//创建学生对象
Student s1=new Student("小A","10");
Student s2=new Student("小B","20");
Student s3=new Student("小C","30");
Student s4=new Student("小D","40");
Student s5=new Student("小D","40");
System.out.println("s4:"+s4.hashCode());
System.out.println("s5:"+s5.hashCode());
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
hs.add(s5);
hs.add(s4);
System.out.println("=========================");
for (Student student : hs) {
System.out.println(student);
}
}
运行结果:
s4:865113938
s5:1442407170
=========================
Student [name=小D, age=40]
Student [name=小B, age=20]
Student [name=小A, age=10]
Student [name=小C, age=30]
Student [name=小D, age=40]
分析:此时会发现s4和s5的哈希值不同,但是s4和s5的成员变量的值都相同,所以集合中出现了重复的元素(此处的重复指的是成员变量值都相同),此时调用的是Object中的hashCode和equals方法,所以就需要在Student类中重写hashCode方法和equals方法。
重写后的Student类:
package com.xiaowen.demo2;
public class Student {
private String name;
private String age;
public Student() {
}
public Student(String name, String age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
//根据成员变量的哈希值和成员变量的值,按照如下规则生成新的哈希值
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
运行结果:此时 s5没有添加到集合中
s4:783066
s5:783066
=========================
Student [name=小D, age=40]
Student [name=小C, age=30]
Student [name=小B, age=20]
Student [name=小A, age=10]
分析:
1、重写hashCode方法,根据成员变量的哈希值和成员变量的值,按照一定的规则生成新的哈希值
2、重写equals方法,比较成员变量的值
补充:
LinkedHashSet:底层数据结构由哈希表和链表组成,其特点是元素唯一且有序