Java集合HashSet基本使用详解
Java集合HashSet基本使用详解
HashSet特点
因为 HashSet是实现了Set接口的,所以特点和Set差不多,都是无序、无下标、元素不重复。
存储结构
HashSet的存储结构在jdk1.7之前是基于数组+链表实现的,在jdk1.8之后是基于数组+链表+红黑树来实现的
存储过程
1、根据hashcode计算保存的位置,如果此位置为空,则直接进行保存,如果不为空则进行第二步
2、执行equals方法,如果equals方法为true,则认为是重复,不继续添加,否则进行添加而形成链表
这里对上面的话简单的进行翻译一下,大家可以设想一下在火车站买门票的情形,多个窗口下排着不同的人群。窗口可以理解为一个连续的数组,分别有自己的下标,而人群则可以理解为挂在下面的元素,存储的结构为链表。所以在整个存储的过程中,根据hashcode值来判断保存在数组的哪一个位置,每个数据元素都有属于自己的hashcode值,切不同元素之间的值可能相同也可能不同。如果hashcode值相同的数则挂在同一个数组下标下。
测试案例
这里我自己新建了一个Person类来进行测试:
package com.HashSet;
public class Person {
private String name;//姓名属性
private int age;//年龄属性
@Override
public String toString() { //重写toString方法,没啥好说
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(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;
}
}
添加和删除数据:
public class Main {
public static void main(String[] args) {
HashSet<Person> hashSet = new HashSet<Person>();
Person p1 = new Person("张三",18);
Person p2 = new Person("李四",20);
Person p3 = new Person("王五",22);
Person p4 = new Person("赵六",21);
//添加元素
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
hashSet.add(p4);
// hashSet.add(p4); //重复添加元素,size不会进行改变
System.out.println("size = "+hashSet.size());//4
System.out.println(hashSet.toString());
//删除
hashSet.remove(p1);
System.out.println("size = "+hashSet.size());//3
}
}
在这里的打印结果如下,没啥好说的:
size = 4
[Person{name='李四', age=20}, Person{name='赵六', age=21}, Person{name='张三', age=18}, Person{name='王五', age=22}]
size = 3
注意事项
下面,可以将问题进行引申,如果我添加写的是 add(new Person(“王五”,22)),会不会重复进行添加?size大小会不会不变?如果删除的是remove(new Person(“王五”,22))那么size会不会减小?
答案是:add会添加成功,size会变大,remove之后的第一个王五没有 被 移除,size大小没有发生改变(不信的同学可以自己跑一遍代码进行演示)。
在这里我们得明白我们想要的功能是什么,按照Set元素的不可重复性,我们应该认为在添加了相同的元素以后size的大小是不能发生改变的,而再删除了王五以后size的大小应该是会变小,在这里却没有得到实现,所以我们应该好好思索一下这个问题。
产生问题的原因就是HashSet的数据存储过程,前面也说了,数据是根据hashcode和equals方法来进行存储的,而我们想要在逻辑上实现我们想要的结果,就必须得对hashcode方法和equals方法按照我们的方式进行重写。
package com.HashSet;
import java.util.Objects;
public class Person {
private String name;
private int age;
//重写equals方法
@Override
public boolean equals(Object o) {
if(o==null) //如果对象为空
return false;
if(o==this) //如果对象是本身
return true;
if(o instanceof Person) //如果对象属于Student类并且属性相等
{
Person p = (Person) o;
if(p.getName().equals(this.name)&&p.getAge()==this.age)
return true;
}
return false;
}
//重写hanshCode方法
@Override
public int hashCode() {
int n1 = this.name.hashCode(); //得到name的hashcode值
int n2 = this.age;
return n1+n2;
}
@Override
public String toString() { //重写toString方法,没啥好说
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Person(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;
}
}
如此一来,问题就可以得到解决了。当然这是我自己重写的hashcode方法和equals方法,如果大家根据自己的需求嫌麻烦的话可以IDE会有自动帮你写的。就想insert构造方法和get、set方法一样。不知道的同学可以到网上去搜索,这里用的是InterJ IDEA,快捷键导入的话是 ALT+INSERT.
后面的元素遍历和判空等基本操作这里就不再进行演示了,因为和之间我写的ArrayList文章差不多,大家如果有可以去参考一下,值得注意的是和ArrayList比起来HashSet进行遍历的话只能用增强for循环和迭代器,不支持for循环,因为没有下标嘛~
上一篇: ubuntu遍历文件夹