目录
1、Set接口
一个不包含重复元素的collection集合。通过元素的equals方法,来判断是否为重复元素。
2、HashSet
- 此类实现Set接口,由哈希表(实际上是一个HashMap实例)支持。他不保证set的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null元素
- HashSet采用哈希表结构存储数据,保证元素唯一性的方式是依赖于:hashCode方法与equals方法
3、HashSet存储数据的结构(哈希表)
- 什么是哈希表?
哈希表底层采用的数组机制,数组中存放对象。在存放对象时,会根据对象在数组中的存放位置,然后把该对象存放到数组中。这样的数组叫做哈希数组(即哈希表)。
- 保证HashSet集合元素的唯一,其实就是根据hashSet和equals方法来决定。
4、HashSet存放JavaAPI中的类型元素
HashSet存放JavaAPI中的类型元素时,不需要重写hashCode和equals方法
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
System.out.println(list);
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
if("a".equals(next)){
list.add("xiaolei"); // 会报错 并发修改异常
}
}
// Set集合存放的元素是无序的
// 同一个哈希码位置可以存放多个元素
}
5、HashSet存储自定义类型元素
需要重写hashCode方法和equals方法,建立自己的比较方式,才能保证HashSet集合中对象的唯一。
- 创建自定义Person类,重写hashCode和equals方法。
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode(){
final int prime = 101;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 :name.hashCode());
return result;
}
public boolean equals(Object object){
if(this == object){
return true;
}if(!(object instanceof Person)){
return false;
}
Person person = (Person) object;
return this.age == person.age && this.name.equals(person.name);
}
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 +
'}';
}
}
- 创建HashSet集合,存储Person对象
public static void main(String[] args) {
HashSet<Person> hashSet = new HashSet<>();
hashSet.add(new Person("小镭",3));
hashSet.add(new Person("小黑",8));
hashSet.add(new Person("小镭",8));
hashSet.add(new Person("小黑",3));
Iterator<Person> iterator = hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
6、LinkedHashSet
LinkedHashSet是链表和哈希表组合的一个数据存储结构
public class SetDemo{
public static void main(String[] args) {
LinkedHashSet<Person> linkedhashset= new LinkedHashSet<>();
linkedhashset.add(new Perons("Xiaolei",1));
linkedhashset.add(new Perons("小黑",10));
Iterator<Person> it = linkedhashset.iterator();
while(it.hashNext){
System.out.println(it,next());
}
}
}
7、判断集合元素唯一的原理
7.1、ArrayList的contains方法判断元素是否重复的原理
- 调用传入对象的equals方法,依次和集合中的旧元素作比较,根据返回的布尔值来判断是否有重复元素
7.2、HashSet的add、contains等方法判断元素是否重复的原理
由于HashSet集合是无序的,其判断唯一依据就是元素类型的hashCode和equals方法的返回结果。规则如下:
先判断元素与集合内已有元素的HashCode值
- 如果不同,说明是不同元素,则添加到集合
- 如果相同,再判断equals方法的比较结果。如果为true,则为相同元素。否则为不同元素,添加到集合。
7.3、hashCode和equals方法的面试题:
- 如果两个对象的哈希值相同,两个对象的equals一定返回true吗?
- 如果两个对象的equals方法返回true,两个对象的哈希值一定相同吗
8、总结
- List集合:它是一个有序的集合,它可以存储重复元素
- Set集合:它是一个无序的集合,它不可以存储重复元素
- ArrayList:底层数据结构是数组:查询快,增删慢
- LinkedList:底层数据结构是链表:查询慢,增删快
- HashSet:元素唯一,不能重复,底层结构是哈希表;元素的存取顺序不能保证一致; 如何保证元素的唯一性? 重写hashCode和equals方法
- LinkedHashSet:元素唯一,不能重复,底层结构是:哈希表结构+链表结构 元素存取顺序一致