public interface Set extends Collection
首先它是一个不包含重复元素的collection,更确切地将,set不满足包含e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个null元素。
在所有构造方法以及 add、equals 和 hashCode 方法的协定上,Set 接口还加入了其他规定,这些规定超出了从 Collection 接口所继承的内容。
set集合基础:
- 实现了collection接口
- set接口的特性:无序的,元素不可重复
- 底层大多数是Map结构的实现
- 常用的三个子类都是非同步的
set接口下面的三个常用子类:
- HashSet(非同步)
- LinkedHashSet(非同步)
- TreeSet(非同步)
set中的常用方法
- add(E e) 如果 set 中尚未存在指定的元素,则添加此元素
- contains(Object o) 如果 set 包含指定的元素,则返回 true
- iterator() 返回在此 set 中的元素上进行迭代的迭代器。
- size() 返回 set 中的元素数(其容量)。
- toArray() 返回一个包含 set 中所有元素的数组
- remove(Object o) 如果 set 中存在指定的元素,则将其移除
- equals(Object o) 比较指定对象与此 set 的相等性
一.HashSet
- HashSet元素唯一,无序(存取顺序不一致)
- HashSet底层数据结构是哈希表(哈希表:是元素为链表的数组,具有链表和数组的特点,JDK1.7之前。JDK1.8数组链表和二叉树)
- 构造一个新的set,其底层HashMap实例的默认初始容量为16,加载因子为0.75
- HashSet底层是用HashMap来存储的
当给HashSet集合中存放一个元素时,HashSet会调用该对象的HashCode()方法,来获得该对象的的HashCode值。然后根据HashCode的值决定该对象在HashSet中存放的位置。
因此在在HashSet中判断两个元素是否相等首先判断两个对象的HashCode值是否相等,然后再判断两个对象的equals()方法的返回值是否相等,只有当这两个都相等的时候才可以说明这两个对象相等。
总的来说HashSet保证元素唯一性是靠元素重写HashCode()和equals()方法来保证的。
二.LinkedHashSet
- 底层数据结构是由哈希表(是一个元素为链表的数组)和双向链表组成。该链表定义了迭代顺序保证元素有序,哈希表保证元素唯一
- 元素有序且唯一(存取顺序一致)
- 元素可以为null
- 实际上就是LInkHashMap
import java.util.LinkedHashSet;
public class MyTest2 {
public static void main(String[] args) {
LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(1);
linkedHashSet.add(4);
linkedHashSet.add(6);
//重复的对象不会再次存储
linkedHashSet.add(6);
linkedHashSet.add(9);
//存取顺序一致
for (Integer integer : linkedHashSet) {
System.out.println(integer);
}
}
}
运行结果为:
1
4
6
9
三.TreeSet
- TreeSet底层数据结构是红黑树,最大的特点是能够对元素进行排序。
- 元素唯一可以排序
- TreeSet元素保证唯一性是靠CompareTo方法的返回值来确定,如果返回为0,就是两个元素相等就不重复存储。
- 元素不能为空
TreeSet有两种排序方式
- 自然排序(使用空参构造用自然排序)
- 使用比较器排序(使用有参构造用比较器排序)
注意:使用TreeSet集合进行元素的自然排序,那么这个元素必须实现Comparable接口,否则无法进行自然排序。
例一 .使用空参构造,对自己定义的学生对象按照年龄进行排序
//Student类
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(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 int compareTo(Student 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 MyTest {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(new Student("海绵宝宝",21));
treeSet.add(new Student("派大星",29));
treeSet.add(new Student("珊迪",25));
treeSet.add(new Student("蟹老板",27));
treeSet.add(new Student("海绵宝宝",24));
for (Student student : treeSet) {
System.out.println(student.getAge()+" "+student.getName());
}
}
}
运行结果为:
21 海绵宝宝
24 海绵宝宝
25 珊迪
27 蟹老板
29 派大星
例二.使用有参构造,对自己定义的学生对象按照名字进行排序
public class Student {
private String name;
private int age;
public Student() {
}
public Student(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;
}
}
import java.util.Comparator;
import java.util.TreeSet;
public class MyTest {
public static void main(String[] args) {
//按照名字排序
Comparator<Student> comparator = new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num1 = s1.getName().length() - s2.getName().length();
int num2=num1==0?s1.getName().compareTo(s2.getName()):num1;
int num3=num2==0?s1.getAge()-s2.getAge():num2;
return num3;
}
};
TreeSet<Student> treeSet = new TreeSet<>(comparator);
treeSet.add(new Student("海绵宝宝",21));
treeSet.add(new Student("派大星",29));
treeSet.add(new Student("珊迪",25));
treeSet.add(new Student("蟹老板",27));
treeSet.add(new Student("海绵宝宝",24));
for (Student student : treeSet) {
System.out.println(student.getAge()+" "+student.getName());
}
}
}
运行结果为:
25 珊迪
29 派大星
27 蟹老板
21 海绵宝宝
24 海绵宝宝