HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的,当向HashSet集合中添加一个对象时,首先会调用对象的hashCode()方法来确定元素的存储位置,然后再调用对象的equals()方法来确保该位置没有重复的元素。Set集合与List集合存取元素的方式都一样。
1.HashSet存储字符串并遍历
package com.first;
import java.util.HashSet;
public class HelloWorld {
public static void main(String[] args) {
HashSet<String> hs=new HashSet<>();
boolean b1=hs.add("a");
boolean b2=hs.add("b");
boolean b3=hs.add("b");
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);
for (String s : hs) {
System.out.println(s);
}
}
运行结果为
true
true
false
b
a
如果添加相同的元素会返回false。
HashSet集合之所以能确保不出现重复的元素,是因为它在存入元素时做了很多工作。当调用HashSet集合的add()方法存入元素时,首先调用当前存入对象的hashCode()方法获得对象的哈希值,然后根据对象的哈希值计算出一个存储位置,如果该位置上没有元素,则直接将元素存入,如果该位置上有元素存在,则会调用equals()方法让当前存入的元素依次和该位置上的元素进行比较,如果返回的结果为true就将元素存入集合,返回的结果为false则说明有重复元素,就将该元素舍弃。
为了保证HashSet正常工作,要求存入对象时,重写该类中的hashCode()和equals()方法。将字符串存入HashSet时,String类已经重写了hashCode()和equals()方法。
2.HashSet存储自定义对象保证元素唯一性。
package com.first;
import java.util.HashSet;
public class HelloWorld {
public static void main(String[] args) {
HashSet<Person> hs=new HashSet<>();
boolean b1=hs.add(new Person("张三",22));
boolean b2=hs.add(new Person("李四",23));
boolean b3=hs.add(new Person("张三",22));
for (Person p : hs) {
System.out.println(p);
}
}
}
class Person{
String name;
int 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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public boolean equals(Object obj) {
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
@Override
public int hashCode() {
return 10;
}
}
运行结果为
Person [name=李四, age=23]
Person [name=张三, age=22]
这里重写了Person类中的equals()和hashCode()方法,hashCode随意返回了一个数字10.
当调用add方法存入对象时,因为调用hashCode时返回的都是相同的值10,所以都会调用equals方法来进行比较。如果没有重写hasCode方法的话,会用其父类Object中的hasCode方法,而这个方法每次生成的值都不同,所以不会调用equals方法进行比较。
但自己重写的这两个方法,效率很低,每次都要调用equals方法。其实这两个方法可以自动生成,用快捷键alt+shift+s+h。
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
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;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
LinkedHashSet
底层是链表实现的,是set集合中唯一一个能保证怎么存就怎么取的集合对象。
因为是HashSet的子类,所以也是保证元素唯一的