HashSet集合概述和特点
特点:
底层数据结构是哈希表
不能保证存储和取出的顺序完全一致
没有带索引的方法,所以不能使用普通for循环遍历
由于是Set集合,所以元素唯一
代码验证
package com.shengda.Demo5HashSet;
import java.util.HashSet;
import java.util.Iterator;
public class Demo1HashSet {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
hs.add("小美美");
hs.add("美羊羊");
hs.add("蓝兔");
hs.add("蓝兔");
Iterator<String> it = hs.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("---------------");
for (String h : hs) {
System.out.println(h);
}
}
}
哈希值
哈希值(哈希码值):是JDK根据对象的地址或者属性值,算出来的int类型的整数。
Object类中有一个方法可以获取对象的哈希值
public int hashCode(): 根据对象的地址值计算出来的哈希值.
对象的哈希值缺点:
如果没有重写hashCode方法,那么是根据对象的地址值计算出的哈希值
同一个对象多次调用hashCode()方法返回的哈希值是相同的
不同对象的哈希值是不一样的
如果重写了hashCode方法,一般都是通过对象的属性值计算出哈希值
如果不同的对象属性值是一样的,那么计算出来的哈希值也是一样的。
Student.java在这里边重写hashCode方法
package com.shengda.Demo5HashSet;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
// 我们可以对Object类中的hashCode方法进行重写
// 在重写之后,就一般是根据对象的属性值来计算哈希值的。
// 此时跟对象的地址值就没有任何关系了
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Demo2HashSet.java
package com.shengda.Demo5HashSet;
/*计算哈希值*/
public class Demo2HashSet {
public static void main(String[] args) {
Student s1 = new Student("m美羊羊", 17);
Student s2 = new Student("l蓝兔", 23);
// 因为在Object类中,是根据对象的地址值计算出来的哈希值
System.out.println(s1.hashCode()); // 189568618
System.out.println(s1.hashCode()); // 189568618
//
System.out.println(s2.hashCode()); // 793589513
}
}
常见数据结构之哈希表
哈希表:
JDK8(不包括8)之前,底层采用数组+链表实现。
JDK8之后,底层进行了优化。由数组+链表+红黑树实现。
HashSet1.7版本原理总结
1.底层结构:哈希表。(数组+链表)
2.数组的长度默认为16,加载因子为0.75
3.首先会先获取元素的哈希值,计算出在数组中应存入的索引。
3.1判断该索引处是否为null
3.2如果是null,直接添加
3.3如果不是null,则与链表中所有的元素,通过equals方法比较属性值
3.4只要有一个相同,就不存,如果都不一样,才会存入集合
HashSet1.8版本原理解析
底层结构:哈希表。(数组+链表+红黑树的结合体)
当挂在下面的元素过多,那么不利于添加,也不利于查询,所以在JDk8之后
当链表长度超过8的时候,自动转换为红黑树
存储的流程不变。
Set集合小结
Set:
无序
无索引
不可以重复
HashSet:
底层:哈希表
重写hashCode和equals方法
TreeSet:
底层:红黑树
必须给定排序规则