探索无边界:Java中Set 集合的无穷魅力

        本人在很多情况下会使用Set集合去做针对数据唯一性的处理,但是Set有那么多种,什么场景使用哪种Set是一个值得思考的问题。希望可以帮助到各位。

一,概念详解:

        Set 是一个不允许包含重复元素的集合。HashSet、TreeSet 和 LinkedHashSet 都是 Set 接口的实现类,它们各自具有不同的特性和使用场景。

  1. HashSet:基于哈希表实现,其元素是无序的。添加、删除和查找操作的时间复杂度都是 O(1)。它不保证元素的顺序,也不允许包含 null 元素。当向 HashSet 集合中添加元素时,它会调用该对象的 hashCode() 方法来决定元素在集合中的存储位置。如果两个对象通过 equals() 方法比较相等,并且它们的 hashCode() 方法返回值也相等,则它们被认为是相等的。
  2. TreeSet:是 SortedSet 的实现类,允许根据元素的自然顺序或者创建时提供的 Comparator 进行排序。它使用树结构(通常是红黑树)来存储元素,因此添加、删除和查找操作的时间复杂度为 O(log n)。TreeSet 允许包含 null 元素,但只能有一个。与 HashSet 相比,TreeSet 在迭代访问集合中的全部元素时性能较好,但在插入元素时的性能较差。
  3. LinkedHashSet:底层数据结构由哈希表和链表组成。它根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的顺序。因此,LinkedHashSet 中的元素顺序与它们被添加到集合中的顺序一致。它不允许有重复的元素,但可以有一个 null 元素。与 HashSet 相比,LinkedHashSet 在插入和访问元素时的性能略逊一筹,但在迭代访问集合中的全部元素时性能较好。个人认为LinkedHashSet相当于List的去重版本(因为List的本身就是有序的)

我这里提供三种模拟现实场景(仅供参考):

场景1:需要快速插入、删除和查找操作且不关心元素的顺序;

场景2:需要一个自动排序的集合(或者有自定义排序需求)如自然数;

场景3:需要保持元素的插入顺序或者对链表操作有特殊需求;

是否能包含null数据结构顺序适用场景
HashSet 否哈希表无序场景1
LinkedHashSet 是(只能一个)红黑树与被添加到集合时的顺序一致场景3
TreeSet 是(只能一个)哈希表和链表允许自然排序或者自定义排序场景2

#自然排序是指根据元素的大小顺序进行排序,要求元素所属的类实现Comparable接口,并重写compareTo方法来定义排序规则

二、代码详解:

HashSet:

(1)对于集合中值为数字的情况 

public static void main(String[] args) {
        HashSet<Integer> set = new HashSet<>();
        set.add(5);
        set.add(2);
        set.add(8);
        set.add(1);
        set.add(2);
        set.add(4);
        for (Integer num : set) {
            System.out.println(num);
        }
    }

结果:

是不是有点疑惑。哈哈哈,那是因为HashSet中数据为数字类型的,由于数字类型的hashCode方法实现可能存在规律性,可能导致元素在桶中的顺序出现一定的规律。所以导致结果是顺序的

(2)对于集合中值为字符串的情况 

public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("我是5");
        set.add("我是2");
        set.add("我是8");
        set.add("我是1");
        set.add("我是2");
        set.add("我是4");
        for (String num : set) {
            System.out.println(num);
        }
    }

结果:

2.LinkedHashSet(顺序与插入顺序一致)

(1)对于集合中值为数字的情况

public static void main(String[] args) {
        LinkedHashSet<Integer> set = new LinkedHashSet<>();
        set.add(5);
        set.add(2);
        set.add(8);
        set.add(1);
        set.add(2);
        set.add(4);
        for (Integer num : set) {
            System.out.println(num);
        }
    }

  结果:

(2)对于集合中值为字符串的情况    

 public static void main(String[] args) {
        LinkedHashSet<String> set = new LinkedHashSet<>();
        set.add("我是5");
        set.add("我是2");
        set.add("我是8");
        set.add("我是1");
        set.add("我是2");
        set.add("我是4");
        for (String num : set) {
            System.out.println(num);
        }
    }

结果:

3.TresSet(自然排序):

(1)对于集合中值为数字的情况

public static void main(String[] args) {
        TreeSet<Integer> set = new TreeSet<>();
        set.add(5);
        set.add(2);
        set.add(8);
        set.add(1);
        set.add(2);
        set.add(4);

        for (Integer num : set) {
            System.out.println(num);
        }
    }

 结果:

(2)对于集合中值为字符串的情况    

 public static void main(String[] args) {
        TreeSet<String> set = new TreeSet<>();
        set.add("我是5");
        set.add("我是2");
        set.add("我是8");
        set.add("我是1");
        set.add("我是2");
        set.add("我是4");
        for (String num : set) {
            System.out.println(num);
        }
    }

  结果如下:

总结:HashSet、TreeSet 和 LinkedHashSet 各有其特点,选择使用哪一种取决于具体的需求和使用场景。如果需要快速插入、删除和查找操作且不关心元素的顺序,可以选择 HashSet;如果需要一个自动排序的集合,可以选择 TreeSet;如果需要保持元素的插入顺序或者对链表操作有特殊需求,可以选择 LinkedHashSet。我们可以先不纠结这些集合的底层逻辑,首先得明白什么场景下使用合适的才是第一步,慢慢掌握底层逻辑。

希望我的文章能帮到您,感谢您的阅读,愿我们共同进步,加油!!

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值