set集合(HashSet、LinkedHashSet、TreeSet)

目录

set集合:Java 中的 Set 是一种集合接口,属于 Java 集合框架(java.util 包)的一部分,它继承自 Collection 接口。Set 集合的核心特点是不允许包含重复元素,并且最多只能包含一个 null 元素(具体取决于HashSet、LinkedHashSet、TreeSet三个实现类)。

一、HashSet:

1、底层原理:

2、主要特性:

(1)无重复元素:添加重复元素时会被自动过滤(add() 方法返回 false),这是通过元素的 hashCode() 和 equals() 方法判断的。

(2)无序性:元素的存储顺序与添加顺序无关,且遍历顺序可能随时间变化(不保证稳定性).

(3)允许 null 元素:但最多只能存储一个 null(因为不允许重复)。

(4)高效性能:添加、删除、查询元素的平均时间复杂度为 O(1),这得益于哈希表的快速访问特性。

(5)非线程安全:多线程环境下需手动同步(如使用 Collections.synchronizedSet() 包装)。

3、初始化:

(1)public HashSet():创建一个默认为空的HashSet

(2)public HashSet(int initialCapacity, float loadFactor):initialCapacity(初始容量)指哈希表在创建时的初始桶(bucket)数量,默认值为 16。容量必须是 2 的幂次方(哈希表会自动调整为最接近的 2 的幂),这是为了优化哈希计算的效率。loadFactor(加载因子)是哈希表扩容的阈值比例,默认值为 0.75f,计算公式:扩容值 = 当前容量 × 加载因子。当元素数量超过阈值时,哈希表会自动扩容(容量翻倍),以减少哈希冲突。

(3)public HashSet(Collection c):创建一个容器内容为c的集合。

4、常用方法:

(1)public boolean add(E e):向集合中添加元素。

(2)public boolean remove(Object o):集合中删除元素。

(3)public void clear():清空集合元素。

(4)public int size():返回集合中元素的数量。

(5)boolean addAll(Collection c): 插入一个collection 集合,插入的时候只要成功的添加一个元素,返回值就为true。

(6)boolean isEmpty():判空

(7)boolean contains(Object o): 判断元素是否存在。

5、集合遍历:

二、LinkedHashSet:

1、底层原理:

2、主要特性:

(1)有序性:与 HashSet 的无序性不同,LinkedHashSet 会通过双向链表记录元素的插入顺序,因此遍历元素时会按照添加顺序输出。有序指的是元素放入的顺序

(2)无重复元素:和所有 Set 实现类一样,LinkedHashSet 不允许存储重复元素,判断重复的逻辑与 HashSet 一致(依赖 hashCode() 和 equals() 方法)。

(3)允许 null 元素:最多只能包含一个 null 元素。

(4)与HashSet 的初始化、常用方法、遍历一样

三、TreeSet:

1、底层实现:

2、主要特性:

(1)有序性:元素会按照自然排序(默认)或自定义排序规则进行排序,而非插入顺序。

(2)无重复元素:与所有 Set 实现类一样,不允许重复元素,重复元素会被自动过滤。

(3)不允许 null 元素:插入 null 会抛出 NullPointerException(因为需要比较元素大小)。

(4)性能:添加、删除、查询元素的时间复杂度为 O(log n),适合需要排序且频繁操作的场景。

(5)非线程安全:多线程环境下需手动同步(如使用 Collections.synchronizedSortedSet() 包装)。

3、初始化:

(1)public  TreeSet(): 构造一个空的有序set集合

(2)public TreeSet(Comparator comparator)构造一个传入排序规则的有序Set集合

(3)public TreeSet(Collection c):构造一个集合元素为c的有序Set集合

4、Set集合如何过滤重复元素

四、HashSet、LinkedHashSet、TreeSet三者区别:


set集合:Java 中的 Set 是一种集合接口,属于 Java 集合框架(java.util 包)的一部分,它继承自 Collection 接口。Set 集合的核心特点是不允许包含重复元素,并且最多只能包含一个 null 元素(具体取决于HashSet、LinkedHashSet、TreeSet三个实现类)。

一、HashSet:

1、底层原理:

    HashSet 内部通过 HashMap 实现(维护一个 HashMap 实例):存储的元素被作为 HashMap 的 key,而 value 则是一个固定的空对象(PRESENT)。元素的去重逻辑依赖于 HashMap 的 key 不重复特性.

2、主要特性:
(1)无重复元素:添加重复元素时会被自动过滤(add() 方法返回 false),这是通过元素的 hashCode() 和 equals() 方法判断的。
(2)无序性:元素的存储顺序与添加顺序无关,且遍历顺序可能随时间变化(不保证稳定性).
(3)允许 null 元素:但最多只能存储一个 null(因为不允许重复)。
(4)高效性能:添加、删除、查询元素的平均时间复杂度为 O(1),这得益于哈希表的快速访问特性。
(5)非线程安全:多线程环境下需手动同步(如使用 Collections.synchronizedSet() 包装)。
3、初始化:
(1)public HashSet():创建一个默认为空的HashSet
(2)public HashSet(int initialCapacity, float loadFactor):initialCapacity(初始容量)指哈希表在创建时的初始桶(bucket)数量,默认值为 16。容量必须是 2 的幂次方(哈希表会自动调整为最接近的 2 的幂),这是为了优化哈希计算的效率。loadFactor(加载因子)是哈希表扩容的阈值比例,默认值为 0.75f,计算公式:扩容值 = 当前容量 × 加载因子。当元素数量超过阈值时,哈希表会自动扩容(容量翻倍),以减少哈希冲突。
(3)public HashSet(Collection<? extends E> c):创建一个容器内容为c的集合。
4、常用方法:
(1)public boolean add(E e):向集合中添加元素。
(2)public boolean remove(Object o):集合中删除元素。
(3)public void clear():清空集合元素。
(4)public int size():返回集合中元素的数量。
(5)boolean addAll(Collection<? extends E> c): 插入一个collection 集合,插入的时候只要成功的添加一个元素,返回值就为true。
(6)boolean isEmpty():判空
(7)boolean contains(Object o): 判断元素是否存在。
       HashSet<String> hs1 = new HashSet<>();
        //添加元素集合
        boolean b1 = hs1.add("曹操");
        hs1.add("周瑜");
        hs1.add("晁盖");
        boolean b2 = hs1.add("曹操");
        System.out.println("第一次添加元素:"+b1);
        System.out.println("第二次添加元素:"+b2);

        //快速生成list集合
        List<String> list = Arrays.asList("小乔","大乔","诸葛亮","晁盖");
        boolean b3 = hs1.addAll(list);  //添加元素集合,只要成功的添加一个元素,返回值就为true
        System.out.println("添加集合是否成功:"+b3);
        System.out.println(hs1);
        System.out.println("元素个数为:"+hs1.size());
        System.out.println("元素是否存在:"+hs1.contains("小乔"));
        System.out.println("元素是否为空:"+hs1.isEmpty());

        //删除
        boolean b1=hs1.remove("小乔");
        System.out.println("删除元素是否成功:"+b1);
        System.out.println(hs1);

        //清空
        hs1.clear();
        System.out.println(hs1);
5、集合遍历:

迭代器遍历:Iterator<E> iterator()

        Iterator<String> itor = hs1.iterator();
        while(itor.hasNext()){
            System.out.println(itor.next());
        }
        System.out.println("===============");
        for (String str:
                hs1) {
            System.out.println(str);
        }

二、LinkedHashSet:

1、底层原理:

       基于 HashMap 实现(与 HashSet 相同),但额外通过链表记录元素顺序,本质是一个 "Linked HashMap" 的 key 集合。  

2、主要特性:
(1)有序性:与 HashSet 的无序性不同,LinkedHashSet 会通过双向链表记录元素的插入顺序,因此遍历元素时会按照添加顺序输出。有序指的是元素放入的顺序
(2)无重复元素:和所有 Set 实现类一样,LinkedHashSet 不允许存储重复元素,判断重复的逻辑与 HashSet 一致(依赖 hashCode() 和 equals() 方法)。
(3)允许 null 元素:最多只能包含一个 null 元素。
(4)与HashSet 的初始化、常用方法、遍历一样

三、TreeSet:

1、底层实现:

   TreeSet 内部依赖 TreeMap 实现(维护一个 TreeMap 实例):存储的元素被作为 TreeMap 的 key,value 是一个固定的空对象(PRESENT)。排序逻辑完全依赖 TreeMap 的 key 排序特性。元素必须可比较(要么实现 Comparable,要么提供 Comparator),否则会抛出 ClassCastException。排序规则需与 equals() 方法保持一致(即 compareTo() 返回 0 时,equals() 应返回 true),否则可能出现逻辑矛盾(如元素被视为不同但排序位置相同)。

2、主要特性:
(1)有序性:元素会按照自然排序(默认)或自定义排序规则进行排序,而非插入顺序。
(2)无重复元素:与所有 Set 实现类一样,不允许重复元素,重复元素会被自动过滤。
(3)不允许 null 元素:插入 null 会抛出 NullPointerException(因为需要比较元素大小)。
(4)性能:添加、删除、查询元素的时间复杂度为 O(log n),适合需要排序且频繁操作的场景。
(5)非线程安全:多线程环境下需手动同步(如使用 Collections.synchronizedSortedSet() 包装)。
3、初始化:
(1)public  TreeSet(): 构造一个空的有序set集合
(2)public TreeSet(Comparator<? super E> comparator)构造一个传入排序规则的有序Set集合
(3)public TreeSet(Collection<? extends E> c):构造一个集合元素为c的有序Set集合
4、Set集合如何过滤重复元素

核心原理:(1)hashCode() 方法:计算元素的哈希值,用于快速定位元素在底层数据结构(如哈希表)中的存储位置。两个相同的元素必须返回相同的哈希值。(2)equals() 方法:用于精确比较两个元素是否为 "逻辑上的相同元素"。当两个元素的哈希值相同时,会通过 equals() 进一步确认是否为重复元素。

自定义对象去重的关键:对于自定义类的对象,需同时重写 hashCode() 和 equals() 方法TreeSet 需保证排序逻辑与 equals() 一致),否则可能导致去重失效。

例如:

package com.yuan.treeset;

import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;

public class Book implements Comparable<Book> {
    private String bookName;
    private String authorName;
    private int pageSize;
    private double price;

    public Book(String bookName, String authorName, int pageSize, double price) {
        this.bookName = bookName;
        this.authorName = authorName;
        this.pageSize = pageSize;
        this.price = price;

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return pageSize == book.pageSize && Double.compare(book.price, price) == 0 && Objects.equals(bookName, book.bookName) && Objects.equals(authorName, book.authorName);
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookName='" + bookName + '\'' +
                ", authorName='" + authorName + '\'' +
                ", pageSize=" + pageSize +
                ", price=" + price +
                '}' + "\n";
    }

    @Override
    public int compareTo(Book o) {
        int result = this.pageSize - o.pageSize;
        if (result == 0) {
            return this.bookName.compareTo(o.bookName);

        }
        return result;
    }


    @Override
    public int hashCode() {
        return Objects.hash(bookName, authorName, pageSize, price);
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

class Demo01 {
    public static void main(String[] args) {
        //TreeSet是可排序的,且唯一的:
        // 在使用TreeSet时需要注意,一定要提供排序规则给对象(泛型类实现comparable接口或者对象提供Comparator对象)

        //1.无参的构造方法,排序规则使用泛型类型这个类定义的排序规则
        //2.有参构造TreeSet(Comparator comparator)排序比较规则按照传入的参数的规则为准
        Set<Book> set = new TreeSet<>();
        Book b1 = new Book("明朝那些事1", "当年明月1", 1231, 89.0);
        Book b2 = new Book("明朝那些事2", "当年明月2", 121, 89.0);
        Book b3 = new Book("明朝那些事3", "当年明月3", 11, 90.0);
        Book b4 = new Book("明朝那些事4", "当年明月1", 1231, 89.0);
        set.add(b1);
        set.add(b2);
        set.add(b3);
        set.add(b4);

        System.out.println(set);
    }

}

class Demo02 {
    public static void main(String[] args) {
        //如果泛型类型不是Comparable类型,必须要提供一个Comparator对象提供比较规则。
        Set<Book> set = new TreeSet<>(new Comparator<Book>() {
            @Override
            public int compare(Book o1, Book o2) {
                //按照书的价格进行比较
                if(o1.getPrice()>o2.getPrice()){
                    return 1;
                }else if (o1.getPrice() == o2.getPrice()) {
                    return 0;
                }else {
                    return -1;
                }
            }
        });
        Book b1 = new Book("明朝那些事1", "当年明月1", 1231, 89.0);
        Book b2 = new Book("明朝那些事2", "当年明月2", 121, 100.0);
        Book b3 = new Book("明朝那些事3", "当年明月3", 11, 90.0);
        Book b4 = new Book("明朝那些事4", "当年明月1", 1231, 89.0);
        set.add(b1);
        set.add(b2);
        set.add(b3);
        set.add(b4);

        System.out.println(set);
    }
}

四、HashSet、LinkedHashSet、TreeSet三者区别:

实现类排序特性底层结构时间复杂度(增删查)
HashSet无序哈希表O (1)(平均)
LinkedHashSet保持插入顺序哈希表 + 链表O (1)(平均)
TreeSet自然排序 / 自定义排序红黑树O(log n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呼哧呼哧.

栓Q!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值