哈希表
- 哈希表是 HashSet 和 HashMap 集合存储数据的结构;
- 在 JDK1.8 之前,哈希表底层采用数组 + 链表实现,即使用数组处理冲突,同一 hash 值的链表都存储在一个数组里,可见哈希值不唯一,不同元素可以有相同的哈希值。但是当位于一个桶中的元素较多,即 hash 值相等的元素较多时,通过 key 值依次查找的效率较低。到了 JDK 1.8(即 Java 8.0 或 JDK 8),哈希表存储采用数组 + 链表 + 红黑树实现,当链表长度超过阈值 8 时,将链表转换为红黑树,这样大大减少了查找时间;
- 简单的来说,哈希表是由数组+链表+红黑树(JDK 1.8 增加了红黑树部分)实现的,如下图所示:
![哈希表](https://i-blog.csdnimg.cn/blog_migrate/f3f6079105aca4cca9e8e23806e1423b.png)
1. 在 HashSet 上的实现逻辑图
- JDK1.8 引入红黑树大程度优化了 HashMap 的性能,那么对于我们来讲保证 HashSet 集合元素的唯一,其实就是根据对象的 hashCode() 和 equals() 方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写 hashCode() 和 equals() 方法建立属于当前对象的比较方式;
![哈希表在 HashSet 上的具体体现](https://i-blog.csdnimg.cn/blog_migrate/bfb9239c5a8e0cbe0d96e7bf5b96b051.png)
2. 在 HashSet 上的 Java 实现
- 给 HashSet 中存放自定义类型元素时,需要重写对象中的 hashCode() 和 equals() 方法,建立自己的比较方式,才能保证 HashSet 集合中的对象唯一;
import java.util.HashSet;
import java.util.Objects;
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class test {
public static void main(String[] args) {
HashSet<Student> stuSet = new HashSet<Student>();
Student stu = new Student("于谦", 43);
stuSet.add(stu);
stuSet.add(new Student("郭德纲", 44));
stuSet.add(new Student("于谦", 43));
stuSet.add(new Student("郭麒麟", 23));
stuSet.add(stu);
for (Student stu2 : stuSet) {
System.out.println(stu2);
}
}
}