Java Set集合
一、概述
一个不包含重复元素的 collection,set 不包含满足 e1.equals(e2)的元素对 e1和 e2,并且最多包含一个 null 元素
-
案例
import java.util.HashSet; public class Test13 { public static void main(String[] args) { HashSet<Integer> set = new HashSet<Integer>(); set.add(1); set.add(1); set.add(2); set.add(3); set.add(4); set.add(4); set.add(4); set.add(5); for (Integer integer : set) { System.out.println(integer); } } } //输出 1 2 3 4 5
-
JDK1.8HashSet看起来是有序的,为什么呢?
引用知乎一篇文章解释,原文链接:
https://www.zhihu.com/question/28414001/answer/40733996
二、HashSet
-
HashSet 底层数据结构是哈希表. HashSet 不是线程安全的 集合元素可以是 null
-
哈希表:是一个元素为链表的数组,综合了数组和链表的优点 (像新华字典一样) (JDK1.7之前),当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
-
两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等时将元素存入集合
-
结论:HashSet 保证元素唯一性是靠元素重写hashCode()和equals()方法来保证的,如果不重写则无法保证
-
HashSet存储自定义对象保证元素唯一性
重写hashCode()和equals()方法
import java.util.Objects; public class Student1 { private String name; private int age; public Student1() { } public Student1(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 boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student1 student1 = (Student1) o; return age == student1.age && Objects.equals(name, student1.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
-
HashSet存储自定义对象保证元素唯一性图解
-
HashSet存储自定义对象并遍历
import java.util.HashSet; public class Test14 { public static void main(String[] args) { HashSet<Student1> set = new HashSet<>(); set.add(new Student1("张三",14)); set.add(new Student1("李四",16)); set.add(new Student1("王五",18)); set.add(new Student1("赵六",11)); for (Student1 s : set) { System.out.println(s); } } }
三、LinkedHashSet
-
数据结构:链表和哈希表,链表保证有序 哈希表保证元素唯一
import java.util.LinkedHashSet; public class Test15 { public static void main(String[] args) { LinkedHashSet<Integer> set = new LinkedHashSet<>(); set.add(1); set.add(2); set.add(3); set.add(4); set.add(4); set.add(5); set.add(6); System.out.println(set); } } //输出 [1, 2, 3, 4, 5, 6]
四、TreeSet
-
TreeSet集合的特点: 底层数据结构是二叉树,元素唯一,他最大的特点是能够对元素进行排序
-
案例
import java.util.TreeSet; public class Test16 { public static void main(String[] args) { TreeSet<Integer> set = new TreeSet<>(); set.add(5); set.add(7); set.add(3); set.add(1); set.add(3); set.add(2); System.out.println(set); } } //输出: [1, 2, 3, 5, 7]
-
排序
- 自然排序
- 使用比较器排序
- 到底使用的是哪一种的排序取决于,构造方法
-
注意:
- 使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素必须实现Comparable接口,否则无法进行自然排序
- 保证元素的唯一性是靠compareTo方法的返回值来确定如果返回0 表示两个元素相等,则不重复存储
-
图解
-
自然排序
public class Student2 implements Comparable<Student2>{ private String name; private int age; public Student2() { } public Student2(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 "Student2{" + "name='" + name + '\'' + ", age=" + age + '}'; } @Override public int compareTo(Student2 s) { int num = this.age-s.age; int num2 = num==0?this.name.compareTo(s.name):num; return num2; } } import java.util.TreeSet; public class Test17 { public static void main(String[] args) { TreeSet<Student2> set = new TreeSet<>(); set.add(new Student2("张三", 18)); set.add(new Student2("李四",12)); set.add(new Student2("王五",14)); set.add(new Student2("赵六",19)); set.add(new Student2("旺财",15)); set.add(new Student2("张三",18)); for (Student2 s : set) { System.out.println(s); } } } //输出 Student2{name='李四', age=12} Student2{name='王五', age=14} Student2{name='旺财', age=15} Student2{name='张三', age=18} Student2{name='赵六', age=19}
-
使用比较器排序
import java.util.Comparator; public class MyComparator implements Comparator<Student3> { @Override public int compare(Student3 s1, Student3 s2) { int num = s1.age-s2.age; int num2 = num==0?s1.name.compareTo(s2.name):num; return num; } } public class Student3 { String name; int age; public Student3() { } public Student3(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student3{" + "name='" + name + '\'' + ", age=" + age + '}'; } } import java.util.TreeSet; public class Test18 { public static void main(String[] args) { TreeSet<Student3> set = new TreeSet<>(new MyComparator()); set.add(new Student3("张三",18)); set.add(new Student3("李四",17)); set.add(new Student3("王五",19)); set.add(new Student3("赵六",20)); set.add(new Student3("张三",18)); for (Student3 s : set) { System.out.println(s); } } } //输出 Student3{name='李四', age=17} Student3{name='张三', age=18} Student3{name='王五', age=19} Student3{name='赵六', age=20}