Java集合框架:深入理解List与Set及其实现类

在Java集合框架中,List和Set是两个最常用的接口,它们各自有着独特的特点和适用场景。本文将详细介绍List和Set的区别,以及HashSet、LinkedHashSet和TreeSet这三个Set接口的主要实现类的特点、使用方法和适用场景。

一、List和Set集合的区别

1. 有序性

  • List:保证按插入顺序排序,元素的有序性是按照添加的先后顺序确定的
  • Set:存储和取出顺序不一致(除LinkedHashSet外)

2. 唯一性

  • List:元素可以重复,允许存储相同的元素
  • Set:元素唯一,不允许存储重复的元素

3. 获取元素方式

  • List:可以通过索引直接操作元素,提供了基于位置的访问方法
  • Set:不能根据索引获取元素,只能通过迭代器或增强for循环遍历

二、HashSet集合

1. HashSet集合的特点

  • HashSet底层使用的是HashMap实现
  • 不能保证元素的顺序,元素是无序的
  • 不能有重复的元素
  • 集合元素值允许为null
  • 线程不安全
  • 性能在Set实现类中通常是最好的

2. HashSet常用方法

① 添加元素:add(Object o)
java 复制代码
HashSet<String> set = new HashSet<String>();
set.add("青城");
set.add("博雅");
System.out.println(set); // 输出顺序不确定
② 获取元素数量:size()

System.out.println(set.size()); // 输出元素个数

③ 删除元素:remove(Object o)

System.out.println(set.remove("博雅")); // 删除成功返回true

④ 判断集合是否为空:isEmpty()

System.out.println(set.isEmpty()); // 集合为空返回true

⑤ 清空集合:clear()

set.clear(); // 移除所有元素

⑥ 使用迭代器遍历:iterator()
java 复制代码
Iterator<String> ite = set.iterator();
while(ite.hasNext()) {
    System.out.println(ite.next());
}
⑦ 判断是否包含元素:contains(Object o)

System.out.println(set.contains("青城")); // 包含返回true

⑧ 使用增强for循环遍历

for (String name : set) {

System.out.println(name);

}

三、LinkedHashSet集合

1. LinkedHashSet集合的特点

  • 元素有序且唯一
  • 链表保证元素有序(插入顺序)
  • 哈希表保证元素唯一
  • 线程不安全
  • 性能略低于HashSet,但高于TreeSet

2. LinkedHashSet的基本使用

① 创建LinkedHashSet
java 复制代码
// 创建一个空的LinkedHashSet
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();

// 创建具有初始容量的LinkedHashSet
LinkedHashSet<Integer> linkedHashSetWithCapacity = new LinkedHashSet<>(10);

// 创建具有初始容量和负载因子的LinkedHashSet
LinkedHashSet<Double> linkedHashSetWithLoadFactor = new LinkedHashSet<>(10, 0.75f);
② 添加元素
java 复制代码
linkedHashSet.add("Apple");
linkedHashSet.add("Banana");
linkedHashSet.add("Cherry");
linkedHashSet.add("Apple"); // 重复元素,不会添加
System.out.println(linkedHashSet); // 输出: [Apple, Banana, Cherry] 保持插入顺序
③ 删除元素
java 复制代码
linkedHashSet.remove("Banana");
System.out.println(linkedHashSet); // 输出: [Apple, Cherry]

linkedHashSet.clear(); // 清空所有元素
④ 检查元素是否存在
java 复制代码
boolean containsApple = linkedHashSet.contains("Apple");
System.out.println("Contains Apple: " + containsApple);
⑤ 获取集合大小
java 复制代码
int size = linkedHashSet.size();
System.out.println("Size: " + size);
⑥ 遍历LinkedHashSet
java 复制代码
// 使用for-each循环遍历
for (String fruit : linkedHashSet) {
    System.out.println(fruit);
}

// 使用Iterator遍历
Iterator<String> iterator = linkedHashSet.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
⑦ 转换为数组
java 复制代码
String[] array = linkedHashSet.toArray(new String[0]);
for (String s : array) {
    System.out.println(s);
}
⑧ 其他常用方法
java 复制代码
// 检查是否为空
boolean isEmpty = linkedHashSet.isEmpty();

// 保留与指定集合相同的元素
LinkedHashSet<String> fruits = new LinkedHashSet<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");

LinkedHashSet<String> toRetain = new LinkedHashSet<>();
toRetain.add("Apple");
toRetain.add("Cherry");

fruits.retainAll(toRetain); // 只保留Apple和Cherry

// 删除与指定集合相同的元素
fruits.removeAll(toRetain);

四、TreeSet集合

1. TreeSet集合的特点

  • TreeSet内部使用的是TreeMap,基于红黑树实现
  • 元素:TreeSet会对插入的数据排序,所以输入顺序和输出顺序不一致
  • 插入数据内部有两种排序方法:自然排序(默认)和定制排序
  • 值不能为null
  • 值唯一
  • 线程不安全
  • 性能在三者中通常是最低的

2. TreeSet的基本使用

① 插入是按自然顺序排序的
java 复制代码
TreeSet ts = new TreeSet();
ts.add("agg");
ts.add("abcd");
ts.add("ffas");
Iterator it = ts.iterator();
while(it.hasNext()) {
    System.out.println(it.next());
}
// 输出:按照字典序排序
// abcd
// agg
// ffas
② 插入自定义对象需要实现Comparable接口
java 复制代码
class Person implements Comparable {
    String name;
    int age;
    
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Object o) {
        Person p = (Person) o;
        // 先对姓名字典序比较,如果相同,比较年龄
        if(this.name.compareTo(p.name) != 0) {
            return this.name.compareTo(p.name);
        } else {
            if(this.age > p.age) return 1;
            else if(this.age < p.age) return -1;
        }
        return 0;
    }
}

public class Test {
    public static void main(String args[]) {
        TreeSet ts = new TreeSet();
        ts.add(new Person("agg", 21));
        ts.add(new Person("abcd", 12));
        ts.add(new Person("ffas", 8));
        ts.add(new Person("agg", 12));
        Iterator it = ts.iterator();
        while(it.hasNext()) {
            Person p = (Person) it.next();
            System.out.println(p.name + ":" + p.age);
        }
    }
}
// 输出:
// abcd:12
// agg:12
// agg:21
// ffas:8

五、HashSet、LinkedHashSet、TreeSet的使用场景

1. HashSet

  • 适用场景:在大多数情况下,HashSet是Set接口的首选实现。它的性能基本上比LinkedHashSet和TreeSet要好,特别是添加和查询操作,这也是使用最多的两个操作。
  • 特点:不关心元素的顺序,只关心元素是否存在。

2. LinkedHashSet

  • 适用场景:只有当要求插入顺序和取出顺序一致的时候才使用LinkedHashSet。LinkedHashSet的查询性能稍慢于HashSet,但它可以维持元素的添加顺序。
  • 特点:需要保持插入顺序,但又需要Set的唯一性特性。

3. TreeSet

  • 适用场景:只有在需要对元素进行排序时使用。当需要按照自然顺序或者自定义顺序对元素进行排序时,TreeSet是最佳选择。
  • 特点:元素有序,但性能相对较低。

总结

在Java集合框架中,List和Set各有其独特的用途和特点。List关注的是元素的索引和顺序,允许重复元素;而Set关注的是元素的唯一性,不关心元素的顺序(除LinkedHashSet外)。
对于Set的实现类:

  • 如果不需要保持任何顺序,优先使用HashSet
  • 如果需要保持插入顺序,使用LinkedHashSet
  • 如果需要元素按照自然顺序或自定义顺序排序,使用TreeSet
    在实际开发中,根据具体需求选择合适的集合类非常重要,这不仅能提高代码的效率,也能使代码更加清晰易懂。理解这些集合类的底层实现原理和特点,有助于我们做出更加合理的选择。
相关推荐
无名-CODING2 小时前
Java集合List详解:从入门到精通
java·windows·list
laplace01232 小时前
JAVA-Redis上
java·redis·spring
啟明起鸣2 小时前
【Go 与云原生】先从 Go 对与云原生的依赖关系讲起,再讲讲 一个简单的 Go 项目热热身
开发语言·云原生·golang
不要喷香水2 小时前
26.java openCV4.x 入门-Imgproc之图像尺寸调整与区域提取
java·人工智能·opencv·计算机视觉
oioihoii2 小时前
《C语言点滴》——笑着入门,扎实成长
c语言·开发语言
脸大是真的好~2 小时前
黑马JAVAWeb - SpringAOP
java
moxiaoran57532 小时前
RestTemplate使用示例
java
Gogo8162 小时前
从 Spring Boot 到 NestJS:模块化设计的哲学差异
java·后端·nestjs
waves浪游2 小时前
基础开发工具(下)
linux·运维·服务器·开发语言·c++