Set系列集合的特点:无序,不重复,无索引。
HashSet:无序、不重复、无索引。
LinkedHashSet:有序、不重复、无索引。
TreeSet:排序、不重复、无索引。
我们来观察一下下面的代码以及运行截图,可以发现其中的特点。
//1创建一个Set集合的对象
Set<Integer> set = new HashSet<>();//创建了一个HashSet的集合对象 无序(一次),不重复,无索引。
set.add(111);
set.add(111);
set.add(222);
set.add(222);
set.add(333);
set.add(333);
set.add(444);
System.out.println(set);
Set<Integer> set1 = new LinkedHashSet<>();// 有序 不重复 无索引
set1.add(111);
set1.add(111);
set1.add(222);
set1.add(222);
set1.add(333);
set1.add(333);
set1.add(444);
System.out.println(set1);
Set<Integer> set2 = new TreeSet<>();// 排序(升序) 不重复 无索引
set2.add(111);
set2.add(111);
set2.add(222);
set2.add(222);
set2.add(333);
set2.add(444);
System.out.println(set2);
HashSet底层原理
哈希值
首先我们先了解一下哈希值
java中每个对象都有自己的哈希值,同一个对象多次调用hashCode()方法是相同的。不同对象的哈希值一般不同,但是也有可能相同。
public static void main(String[] args) {
Student s1 = new Student("孙悟空",25,169.2);
Student s2 = new Student("牛魔王",25,169.2);
System.out.println(s1.hashCode());
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
String str1 = new String("abc");
String str2 = new String("acD");
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
}
运行结果:
显然可以验证上述观点。
HashSet集合的底层原理
基于哈希表实现
哈希表是一种增删改查数据,性能都比较好的数据结构
JDK8之前:基于哈希树:数组+链表。
JDK8(优化)开始:基于哈希树:数组+链表+红黑树。
LinkedHashSet的底层原理
基于哈希表实现
优化:它的每个元素都额外的多一个双链表机制记录它前后元素的位置。
TreeSet
特点:不重复,无索引,可排序(默认是升序)
底层是基于红黑树实现的。
TreeSet对对象进行有序排序,需要继承接口并且重写方法
public static void main(String[] args) {
Set<Student> students = new TreeSet<>();
students.add(new Student("张三",23,169.5));
students.add(new Student("李四",24,164.5));
students.add(new Student("王五",25,163.5));
System.out.println(students);
}
public class Student implements Comparable<Student> {
private String name;
private int age;
private double height;
public Student() {
}
//重写后:只要两个对象的内容一样,那么就会返回true。
@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 &&
Double.compare(student.height, height) == 0 &&
Objects.equals(name, student.name);
}
//重写后:只要两个对象的内容一样,返回的哈希值就是一样的。
@Override
public int hashCode() {
return Objects.hash(name, age, height);
}
public Student(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
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 double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
@Override
public int compareTo(Student o) {
//如果左边对象大于右边对象返回正整数
//如果左边对象小于右边对象返回负整数
//如果左边对象等于右边对象返回0
return this.age - o.age;
}
}