Set集合
HashSet集合
java.util.HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。
HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode与equals方法。
特点:
- 不允许重复元素
- 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
- 是一个无序的集合,存储元素和取出元素的顺序有可能不一致
- 底层是一个哈希表结构(查询的速度非常的快)
- HashSet是异步的,则必须通过代码来保证同步
HashSet集合存储数据的结构(哈希表):
是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址是模拟出来得到的地址,不是数据实际存储的地址)
jdk1.8之前 哈希表 = 数组 + 链表
jdk1.8之后 哈希表 = 数组 + 链表 + 红黑树(提高查询的速度),
当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
特点:查询速度快
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
- add() 添加
- 注解:HashSet的add()方法,首先会使用当前集合中的每一个元素和新添加的元素进行hash值比较, 如果hash值不一样,则直接添加新的元素 如果hash值一样,比较地址值或者使用equals方法进行比较 比较结果一样,则认为是重复不添加 所有的比较结果都不一样则添加
LinkedHashSet集合
虽然LinkedHashSet使用了链表记录集合元素的添加顺序,但是LinkedHashSet依然是HashSet,因此它依然不允许集合元素重复。
TreeSet集合
TreeSet是SortedSet接口的实现类,TreeSet是有序集合。
使用TreeSet集合的类必须实现Comparable接口,否则程序将会抛出异常。
定制排序
public class AssembleDemo {
int age;
public AssembleDemo(int age) {
this.age = age;
}
@Override
public String toString() {
return "AssembleDemo{" +
"age=" + age +
'}';
}
public static void main(String[] args) {
TreeSet treeSet = new TreeSet((o1, o2) -> {
AssembleDemo m1 = (AssembleDemo) o1;
AssembleDemo m2 = (AssembleDemo) o2;
return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0;
});
treeSet.add(new AssembleDemo(45));
treeSet.add(new AssembleDemo(25));
treeSet.add(new AssembleDemo(41));
treeSet.add(new AssembleDemo(32));
System.out.println(treeSet);
}
}
Set集合的性能分析
HashSet和TreeSet是Set的两个典型实例,HashSet的性能比TreeSet好(特别是最常用的添加、查询元素等操作),因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet。
HashSet还有一个子类:LinkedHashSet,对于普通的插入、删除操作,LinkedHashSet比HashSet要略微慢一点,这是由维护链表所带来的额外开销造成的,但由于有了链表,遍历LinkedHashSet会更快。
EnumSet是所有Set实现类中性能最好的,但它只能保存同一个枚举类的枚举值作为集合元素。
Set的三个实现类都是线程不安全的,通常可以通过Collections工具类的synchronizedSortedSet方法来包装该Set集合。此操作最好在创建时进行,以防止对Set集合的意外非同步访问。
SortedSet s = Collections.synchronizedNavigableSet(new TreeSet<>(...));