HashSet是一个没有重复元素的集合,不保证元素的顺序,而且HashSet允许有null元素。HashSet是采用哈希算法实现,底层实际是用HashMap实现的,因此,查询效率和增删效率都比较高。
1.Hash算法原理
Hash算法也称之为散列算法。Hash算法就是存储规则的变化,将数据打散。
26模9=8,放在索引位置为8的位置,15模9=6,放在索引位置为6的位置,22模9=4,放在索引位置为4的位置,24模9为6,已经存在,往后放,放到索引为7的位置。
2.Hash算法的使用
import java.util.Set;
import java.util.*;
public class HashSetTest {
public static void main(String[] args) {
//实例化HashSet
Set<String> set = new HashSet<>();
//添加元素,注意观察结果,不能有重复元素,添加顺序问题
set.add("a");
set.add("b1");
set.add("c2");
set.add("d");
set.add("a");
//获取元素,在Set容器中,没有索引,所以没有对应的get(int index)方法
for(String str:set) {
System.out.println(str);
}
System.out.println("------删除元素------");
//删除元素
boolean flag = set.remove("c2");
for(String str:set) {
System.out.println(str);
}
System.out.println("------元素个数------");
int size = set.size();
System.out.println(size);
//Collection下的接口函数都可以用,参考ArrayList
}
}
/*
a
d
b1
c2
------删除元素------
a
d
b1
------元素个数------
3
*/
3.HashSet的存储特征
HashSet是一个不保证元素的顺序且没有重复元素的集合,是线程不安全的。HashSet允许有null元素。
无序:
在HashSet中底层是使用HashMap存储元素的,HashMap底层使用的是数组与链表实现元素的存储。元素在数组中存放时,并不是有序存放的也不是随机存放的,而是对元素的哈希值进行运算决定元素在数组中的位置。
数组的默认长度是16,用重写Hashcode的方法,返回 一个int类型的整数,进行哈希算法运算。
不重复:
当两个元素的哈希值进行运算后得到相同的在数组中的位置时,会调用元素的equals()方法判断两个元素是否相同。如果元素相同则不会添加该元素,如果不相同则会使用单向链表保存该元素。这里需要注意,这就是为什么说HashMap底层使用的是数组与链表,这里模相同并没有移到下一位,而是利用单向链表进行存储。
4.通过HashSet存储自定义对象
在这里通过HashSet存储自定义对象,注意,如果存储相同的自定义对象需要重写hashCode和equals方法
未重写之前
//Users类
public class Users {
private String username;
private int userage;
public Users(String username,int userage) {
this.username = username;
this.userage = userage;
}
public Users() {
}
public void setUsername(String username) {
this.username=username;
}
public String getUsername() {
return username;
}
public void setUserage(int userage) {
this.userage = userage;
}
public int getUserage() {
return userage;
}
@Override
public String toString() {
return "Users{"+"username='"+username+'\''+",userage="+userage+'}';
}
}
重写之后
public class Users {
private String username;
private int userage;
public Users(String username,int userage) {
this.username = username;
this.userage = userage;
}
public Users() {
}
public void setUsername(String username) {
this.username=username;
}
public String getUsername() {
return username;
}
public void setUserage(int userage) {
this.userage = userage;
}
public int getUserage() {
return userage;
}
@Override
public String toString() {
return "Users{"+"username='"+username+'\''+",userage="+userage+'}';
}
@Override
public boolean equals(Object o){
if(this == o ) return true;
if(o==null||getClass()!=o.getClass()) return false;
Users users = (Users) o;
if(userage != users.userage) return false;
return username != null ? username.equals(users.username):true;
}
@Override
public int hashCode() {
int result = username!=null ? username.hashCode():0;
result = 31*result+userage;
return result;
}
}
测试
public class HastSetTest02 {
public static void main(String[] args) {
//实例化Hashset
Set<Users> set = new HashSet<>();
Users u1 = new Users("li1",3);
Users u2 = new Users("li1",3);
set.add(u1);
set.add(u2);
//观察哈希值,不相同,解决方法是重写equals和hashCode代码
System.out.println(u1.hashCode());
System.out.println(u2.hashCode());
for(Users u:set) {
System.out.println(u.toString());
}
}
}
/*
未重写结果
793589513
1313922862
Users{username='li1',userage=3}
Users{username='li1',userage=3}
重写结果
3319855
3319855
Users{username='li1',userage=3}
*/