Wend看源码-Java-集合学习(Set)

概述

       Wend看源码-Java-集合学习(List)-CSDN博客 

        在上一篇文章中,我们深入探讨了Java集合框架的父类以及List集合的细节。接下来,本文将重点阐述Java中的Set集合,包括其内部的数据结构以及核心方法的详尽说明。


Set 集合

图1 java-Set类型数据结构类图


Set 接口

        如图1 java-Set类型数据结构类图所示,Set接口继承自 Collection 接口,而Set集合数据类型的相关实现均需要实现Set接口。以下是Set接口的主要方法列表:

  • size:返回集合中元素的数量(集合的基数)。如果元素数量超过Integer.MAX_VALUE,则返回Integer.MAX_VALUE

  • isEmpty:判断集合是否为空。如果集合不包含任何元素,则返回true

  • contains:检查集合是否包含指定元素

  • toArray:返回一个包含集合中所有元素的数组。如果集合对其迭代器返回元素的顺序有任何保证,那么这个方法返回的元素顺序必须与之相同。返回的数组是 “安全的”,即集合不会维护对它的引用,调用者可以自由修改返回的数组。这是数组和集合 API 之间的桥梁方法。

  • add:如果指定元素尚未存在于集合中,则将其添加到集合(这是一个可选操作)。更正式地说,如果集合不包含元素e2使得Objects.equals(e, e2)true,则将指定元素e添加到集合。如果集合已经包含该元素,则调用此方法不会改变集合,并返回false。结合构造函数的限制,这确保了集合从不包含重复元素。可能会抛出UnsupportedOperationException(如果集合不支持add操作)、ClassCastException(如果指定元素的类阻止其被添加到集合)、NullPointerException(如果指定元素为null且集合不允许null元素)或IllegalArgumentException(如果指定元素的某些属性阻止其被添加到集合)。

  • remove:如果指定元素存在于集合中,则将其从集合中移除(这是一个可选操作)。更正式地说,移除一个元素e,使得Objects.equals(o, e)true(如果集合包含这样的元素)。如果集合包含该元素,则返回true(或者等价地说,如果调用导致集合发生变化,则返回true)。一旦调用返回,集合将不再包含该元素。可能会抛出ClassCastException(如果指定元素的类型与集合不兼容)、NullPointerException(如果指定元素为null且集合不允许null元素)或UnsupportedOperationException(如果集合不支持remove操作)。

  • containsAll:如果集合包含指定集合中的所有元素,则返回true。如果指定集合也是一个集合,此方法返回true表示它是这个集合的子集。可能会抛出ClassCastException(如果指定集合中一个或多个元素的类型与这个集合不兼容)、NullPointerException(如果指定集合包含一个或多个null元素且这个集合不允许null元素,或者指定集合为null。

  • addAll:将指定集合中的所有元素添加到这个集合中(如果它们尚未存在)(这是一个可选操作)。如果指定集合也是一个集合,addAll操作实际上会修改这个集合,使其值为两个集合的并集。如果在操作过程中指定集合被修改,操作的行为是未定义的。可能会抛出UnsupportedOperationException(如果集合不支持addAll操作)、ClassCastException(如果指定集合中一个元素的类阻止其被添加到这个集合)、NullPointerException(如果指定集合包含一个或多个null元素且这个集合不允许null元素,或者指定集合为null)或IllegalArgumentException(如果指定集合中一个元素的某些属性阻止其被添加到这个集合)。

  • retainAll:仅保留集合中包含在指定集合中的元素(这是一个可选操作)。换句话说,从集合中移除所有不在指定集合中的元素。如果指定集合也是一个集合,此操作实际上会修改这个集合,使其值为两个集合的交集。可能会抛出UnsupportedOperationException(如果集合不支持retainAll操作)、ClassCastException(如果集合中一个元素的类与指定集合不兼容)、NullPointerException(如果集合包含null元素且指定集合不允许null元素,或者指定集合为null)。

  • removeAll:从集合中移除所有包含在指定集合中的元素(这是一个可选操作)。如果指定集合也是一个集合,此操作实际上会修改这个集合,使其值为两个集合的不对称差集。可能会抛出UnsupportedOperationException(如果集合不支持removeAll操作)、ClassCastException(如果集合中一个元素的类与指定集合不兼容)、NullPointerException(如果集合包含null元素且指定集合不允许null元素,或者指定集合为null)。

  • clear:移除集合中的所有元素(这是一个可选操作)。可能会抛出UnsupportedOperationException(如果集合不支持clear方法)。

  • of:返回一个包含零个元素的不可修改集合。从 Java 9 开始可用,详情可参考Unmodifiable Sets部分。

  • copyOf:返回一个包含给定集合元素的不可修改集合。给定集合必须不为null,且不能包含null元素。如果给定集合包含重复元素,会保留其中一个。如果给定集合后续被修改,返回的集合不会反映这些修改。如果给定集合是一个不可修改集合,调用copyOf通常不会创建副本。从 Java 10 开始可用。

AbstractSet

  AbstractSet是一个抽象类,它实现了Set接口。它位于 Java 集合框架中,主要作用是为Set接口提供一个部分实现,作为创建自定义Set实现类的基础。这个抽象类减少了实现Set接口时需要编写的代码量,因为它已经实现了Set接口中的一些通用方法,同时将某些方法定义为抽象方法,强制子类去实现这些特定的功能。

        一些常见的Set实现类,如HashSetTreeSet间接继承自AbstractSetHashSet继承自AbstractSet并且实现了Set接口。它利用哈希表来存储元素,提供了快速的添加、删除和查找操作。TreeSet同样继承自AbstractSet,它实现了SortedSet接口,在AbstractSet的基础上提供了排序功能,其元素是按照自然顺序或者自定义的比较器顺序存储的。

EnumSet

  EnumSet是一个专门用于处理枚举类型(enum)的集合类。它是一个抽象类,提供了一系列高效的方法来操作基于枚举类型的集合。EnumSet的实现基于位向量(bit - vector),这种实现方式使得它在存储和操作枚举集合时非常高效,特别是在判断元素是否属于集合、集合的并集、交集、差集等操作上。

内部实现原理

        基于位向量的实现意味着对于一个枚举类型,EnumSet可以使用一个整数(或多个整数,取决于枚举类型的大小)的二进制位来表示集合中的元素。每个枚举值对应一个二进制位,当该位为 1 时,表示对应的枚举值在集合中;当该位为 0 时,表示不在集合中。例如,如果有一个包含三个枚举值的枚举类型,EnumSet可以用一个 3 位的二进制数来表示集合中的元素情况。这种实现方式使得集合操作(如添加、删除、包含判断等)可以通过位运算来高效地完成。

使用示例

        以DayOfWeek枚举为例,我们可以使用EnumSet来表示一个工作日的集合:

import java.util.EnumSet;
enum DayOfWeek {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public class EnumSetExample {public static void main(String[] args) {EnumSet<DayOfWeek> workDays = EnumSet.of(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY,DayOfWeek.THURSDAY, DayOfWeek.FRIDAY);System.out.println("是否包含周三:" + workDays.contains(DayOfWeek.WEDNESDAY));}
}
优势与应用场景
  • 性能优势:由于基于位向量的实现,在进行集合操作(如交集、并集、差集等)时,速度非常快。与使用普通的集合类(如HashSet)相比,EnumSet在处理枚举类型的集合操作时可以提供更高的性能。

  • 类型安全:键的类型被限制为枚举类型,保证了类型安全。

  • 应用场景:适用于任何需要处理枚举类型集合的场景,如权限管理(将不同的权限用枚举表示,然后使用EnumSet来管理用户拥有的权限集合)、任务调度(将一周中的工作任务日用枚举表示,然后用EnumSet来确定任务的执行日期集合)等。

RegularEnumSet 

  RegularEnumSet 使用一个长整型(long)数组来表示集合中的元素,每个枚举常量对应数组中的一个位。这种实现方式使得 EnumSet 在添加、删除和检查元素存在性时非常高效。

  • 大小限制:由于 RegularEnumSet 使用 long 数组,它只能容纳最多 64 个枚举常量。如果枚举类型包含超过 64 个元素,EnumSet 会使用另一个内部类 JumboEnumSet 来实现。

  •  内存效率:由于 RegularEnumSet 使用位操作来存储枚举值,因此它非常节省内存。

  • 不可变性:RegularEnumSetEnumSet 一样,不允许存储 null 值,并且所有的枚举类型必须属于同一个枚举类型。

JumboEnumSet

    JumboEnumSetEnumSet的一种特殊实现,用于当枚举常量数量超过特定阈值(通常是 64 个,因为long类型的位长度为 64 位)时高效地存储和操作枚举集合。

  • 基于数组的存储方式:当枚举类型的常量数量较多时,JumboEnumSet内部使用一个long数组来存储枚举集合的信息。每个long值的二进制位用于表示枚举常量是否在集合中。这与普通EnumSet(在元素数量较少时)基于单个long值的位向量表示有所不同。

HashSet

        HashSet 是基于哈希表(实际上是一个 HashMap 实例)来存储元素的。哈希表的作用是通过一个哈希函数将元素的存储位置与元素本身关联起来,这样可以快速地进行元素的添加、删除和查找操作。

主要特点
  • 不重复性:像其他 Set 接口的实现一样,HashSet 不允许有重复的元素。当试图添加一个已经存在于 HashSet 中的元素时,这个添加操作会被忽略。例如,HashSet<String> set = new HashSet<>(); set.add ("apple"); set.add ("apple"); 此时,HashSet 中只会有一个 "apple" 元素。

  • 无序性:HashSet 中的元素是没有固定顺序的。这是因为元素的存储位置是由哈希函数决定的,并不是按照元素添加的先后顺序或者其他自然顺序(如数字大小、字母顺序等)来排列。例如,HashSet<Integer> numbers = new HashSet<>(); numbers.add (3); numbers.add (1); numbers.add (2); 在遍历这个 HashSet 时,元素的出现顺序可能是随机的,比如可能是 2,1,3 或者 3,2,1 等顺序。

  • 高性能的操作:由于基于哈希表实现,HashSet 在添加、删除和查找元素方面通常具有较高的性能。添加一个元素时,通过计算元素的哈希值来确定其在哈希表中的存储位置,这个过程的时间复杂度通常在理想情况下接近常数时间 O (1)。查找和删除元素也是类似的,通过计算元素的哈希值快速定位到可能的存储位置,然后进行比较操作来确定元素是否存在或者进行删除。

应用场景
  • 数据去重:当需要对一组数据进行去重处理时,HashSet 是一个很好的选择。例如,从一个包含重复元素的数组或者列表中获取不重复的元素集合。假设我们有一个包含多个学生姓名的列表,其中可能有重复的姓名,通过将列表中的元素添加到 HashSet 中,可以快速得到不重复的学生姓名集合。

  • 快速查找元素是否存在:如果需要频繁地检查一个元素是否在一个集合中,HashSet 的高性能查找特性可以发挥作用。比如,在一个用户权限管理系统中,有一个存储了所有有效权限名称的 HashSet,当需要验证用户是否具有某个特定权限时,可以快速在这个 HashSet 中进行查找。

SequencedSet

        SequencedSet是 Java 21 新增的接口,用于表示具有明确顺序的集合。它继承了Set的特性(元素的唯一性),同时也具备SequencedCollection的顺序相关特性,提供了方法来访问第一个和最后一个元素,以及在集合的开头或结尾添加或删除元素,并且保证集合中的元素是唯一的。

SortedSet

  SortedSet继承自Set接口和SequencedSet接口。在 Java 中,它代表一个按照自然顺序(例如数字的大小顺序、字符串的字典序等)或者通过提供的Comparator进行排序的元素集合。集合中的元素是唯一的,就像普通的Set一样,不允许有重复元素。

NavigableSet

        NavigableSet是 Java 集合框架中的一个接口,它继承自SortedSet接口。它提供了用于导航和操作有序集合的方法,允许在集合中方便地查找元素,获取比给定元素大或小的元素,以及以正向或反向的顺序遍历集合。

  • 查找操作相关方法

    • lower:返回集合中小于指定元素的最大元素。如果不存在这样的元素,则返回null。例如,在一个存储整数的NavigableSet中,lower(5)会返回小于 5 的最大整数。

    • higher:返回集合中大于指定元素的最小元素。如果不存在这样的元素,则返回null

    • ceiling:返回集合中大于或等于指定元素的最小元素。如果不存在这样的元素,则返回null

    • floor:返回集合中小于或等于指定元素的最大元素。如果不存在这样的元素,则返回null

TreeSet

        TreeSet 实现了 Set 接口,并且底层使用红黑树这种数据结构来存储元素。TreeSet 中的元素是有序的,具体来说,它们按照自然顺序或者通过构造器中指定的 Comparator 进行排序。以下是 TreeSet 的一些关键特性:

关键特性
  1. 有序性:TreeSet 中的元素按照某种排序顺序排列,默认是自然排序,也可以在创建 TreeSet 时提供一个 Comparator 来定义排序规则。

  2. 唯一性:TreeSet 不允许重复元素,如果尝试添加一个已经存在的元素,则添加操作不会成功。

  3. 非同步:TreeSet 不是线程安全的,如果多个线程同时访问 TreeSet,并且至少有一个线程修改了集合,则必须外部同步。

  4. 基于红黑树实现:TreeSet 底层使用红黑树,这是一种自平衡的二叉搜索树,能够保证插入、删除和查找操作的最坏情况时间复杂度为 O(log n)。

示例
import java.util.TreeSet;public class TreeSetExample {public static void main(String[] args) {TreeSet<Integer> treeSet = new TreeSet<>();treeSet.add(10);treeSet.add(5);treeSet.add(20);treeSet.add(15);System.out.println(treeSet); // 输出 [5, 10, 15, 20]// 检索第一个元素System.out.println("First: " + treeSet.first()); // 输出 5// 检索最后一个元素System.out.println("Last: " + treeSet.last()); // 输出 20// 移除一个元素treeSet.remove(10);System.out.println(treeSet); // 输出 [5, 15, 20]}
}

线程安全的Set集合

CopyOnWriteArraySet

        CopyOnWriteArraySet 其内部是通过一个 CopyOnWriteArrayList 来实现的。CopyOnWrite(写时复制)是一种并发编程中的设计模式。当对集合进行修改操作(如添加、删除元素)时,它会先复制一份原有的数据,然后在新的数据副本上进行修改操作,最后将引用指向新的数据。这样做的好处是在读取数据时可以不用加锁,因为在修改数据时不会影响到正在读取数据的线程,从而实现了读写分离,提供了很好的读性能。

多线程下频繁读取场景

        当在多线程环境中,集合的读取操作远远多于修改操作时,CopyOnWriteArraySet 是一个很好的选择。例如,在一个配置管理系统中,有多个线程需要读取配置信息(存储在集合中),而配置信息的修改相对较少,使用 CopyOnWriteArraySet 可以保证读取操作的高效性,同时保证在修改配置时的线程安全性。

ConcurrentSkipListSet

        ConcurrentSkipListSet 是一个支持并发操作的有序集合类,它实现了 SortedSet 接口。它是基于跳表(Skip List)数据结构来实现的。跳表是一种可以高效地进行插入、删除和查找操作的有序数据结构,它通过在原始链表的基础上添加多层索引链表来提高操作效率。在并发环境下,多个线程可以同时安全地访问和修改这个集合。

主要特点
  • 线程安全的并发操作:在多线程环境下,可以同时对集合进行添加、删除和查找操作,并且这些操作是线程安全的。例如,在一个有多个线程同时操作一个 ConcurrentSkipListSet 的场景中,不会出现数据不一致或者并发访问异常的情况,每个线程的操作都能正确地执行,就像操作一个普通的集合一样,只是在内部实现上通过复杂的并发控制机制来保证安全性。
  • 有序性:和其他实现了 SortedSet 接口的集合一样,ConcurrentSkipListSet 中的元素是有序的。元素可以按照自然顺序(如果元素类型实现了 Comparable 接口)或者通过提供的 Comparator 来排序。例如,对于存储整数的 ConcurrentSkipListSet,元素会按照从小到大的顺序排列;如果是存储自定义对象,并且提供了 Comparator,会根据 Comparator 的规则来排序。
  • 高性能的范围查询:由于其基于跳表的数据结构,在进行范围查询时(如查找大于某个值且小于另一个值的所有元素)具有较高的性能。例如,在一个存储时间戳的 ConcurrentSkipListSet 中,可以快速地查询出在某个时间段内的所有时间戳,这对于一些时间序列数据的处理非常有用。
并发环境下的有序数据存储和查询

        在多线程环境下,当需要存储有序数据并且频繁进行添加、删除和范围查询操作时,ConcurrentSkipListSet 是一个很好的选择。比如,在一个分布式系统的任务调度器中,有多个线程需要添加任务(每个任务有一个优先级),同时需要根据优先级范围来查询任务,使用 ConcurrentSkipListSet 可以很好地满足这些需求。

参考文献

豆包

相关文章推荐

Wend看源码-Java-集合学习(List)-CSDN博客

Wend看源码-Java-集合学习(Queue)-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/496815.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

双闭环直流调速系统

一 设计要求 1、原始条件 主要参数&#xff1a;直流电机PN 22KW&#xff0c;额定电压UN220V&#xff0c; 额定电流IN106A&#xff0c;nN 1500r/min&#xff0c;电枢绕组电阻Ra 0.11Ω&#xff0c;主电路总电阻R0.32Ω&#xff0c;磁极对数P2&#xff0c; Ks22&#xff0c;GD2…

word无法创建工作文件,检查临时环境变量。

word无法创建工作文件&#xff0c;检查临时环境变量。 word preview版本&#xff0c;关联打开文件出现报错。word无法创建工作文件&#xff0c;检查临时环境变量。 打开注册表&#xff0c;删除键 Word Preview: HKCR\CLSID{84F66100-FF7C-4fb4-B0C0-02CD7FB668FE} PowerPoint …

Excel将混乱的多行做成1列

目标是将数据按从左到右&#xff0c;再从上到下排成一列。 公式法 首先用textjoin函数将文本包起来&#xff0c;做成一个超长文本。 然后用公式 截取文本 Mid(m1,n,3)&#xff0c;意思就是对m1单元格&#xff0c;从第n个字符开始&#xff0c;截取3个字符出来。 这个公式如何自…

深入解析MySQL索引结构:从数组到B+树的演变与优化

前言&#xff1a; 在数据库查询中&#xff0c;索引是一种关键的性能优化工具。然而&#xff0c;索引的失效可能导致查询效率大幅下降。为了更好地理解索引的工作原理及规避其失效&#xff0c;深入了解索引结构的演变过程尤为重要。 MySQL 的索引数据结构从简单到复杂&#xff0…

怎么把多个PDF合并到一起-免费实用PDF编辑处理工具分享

>>更多PDF文件处理应用技巧请前往 96缔盟PDF处理器 主页 查阅&#xff01; 序言 我之前的文章也有介绍过如何使用96缔盟PDF处理器对PDF文件合并或者批量合并的介绍&#xff0c;但是当时是使用DMPDFUtilTool1.0版本进行的&#xff0c;当时的功能尚不完善&#xff0c;还不支…

medical meadow medical flashcards

“medalpaca/medical_meadow_medical_flashcards” 是一个在 Hugging Face 数据集平台上可用的数据集。这个数据集主要面向医学领域&#xff0c;包含了大量的医学知识卡片&#xff0c;这些卡片由医学生创建和更新&#xff0c;旨在帮助学习和记忆重要的医学概念。以下是关于这个…

新品:SA628F39大功率全双工音频传输模块

SA628F39是一款高集成度的8W大功率全双工无线数据语音一体通话模块&#xff0c;专为高效、稳定的远程通信设计。该模块内置高速微控制器、高性能射频芯片、功率放大器、ESD静电保护和硬件看门狗芯片&#xff0c;具备反接保护、过流过压保护和防死机保护等多重安全功能&#xff…

moviepy将图片序列制作成视频并加载字幕 - python 实现

DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(free)” -------------------------------------------------------------…

面试突击-JAVA集合类(持续更新...)

前言 这篇文档非常适合面试突击人群&#xff0c;java集合类是面试高频问点&#xff0c;阅读完此文章可以直接应对面试官一切问题&#xff0c;最终吊打面试官。 概览 Java 集合&#xff0c;也叫作容器&#xff0c;主要是由两大接口派生而来&#xff1a;一个是 Collection接口&am…

如何计算相位差

如何计算相位差 假设我们有两个同频率的正弦信号&#xff1a; 这里两个信号的角频率w2πf是相同的&#xff0c;根据同频正弦信号相位差的计算方法&#xff0c;直接用两个信号的相位相减。 再来看利用波形图计算相位差的例子&#xff1a; 另一种计算方式&#xff1a;

龙智出席2024零跑智能汽车技术论坛,分享功能安全、需求管理、版本管理、代码扫描等DevSecOps落地实践

龙智快讯 2024年12月5日&#xff0c;由零跑和盖世汽车主办的“2024零跑智能汽车技术论坛”在杭州零跑总部圆满落幕。此次技术论坛聚焦AI语言大模型、AUTOSAR AP平台、DevOps、端到端自动驾驶等热点话题展开探讨&#xff0c;旨在推动智能汽车技术的创新与发展。 龙智作为国内领先…

剑指Offer|LCR 014. 字符串的排列

LCR 014. 字符串的排列 给定两个字符串 s1 和 s2&#xff0c;写一个函数来判断 s2 是否包含 s1 的某个变位词。 换句话说&#xff0c;第一个字符串的排列之一是第二个字符串的 子串 。 示例 1&#xff1a; 输入: s1 "ab" s2 "eidbaooo" 输出: True 解…

LabVIEW条件配置对话框

条件配置对话框&#xff08;Configure Condition Dialog Box&#xff09; 要求&#xff1a;Base Development System 当右键单击**条件禁用结构&#xff08;Conditional Disable Structure&#xff09;**并选择以下选项时&#xff0c;会显示此对话框&#xff1a; Add Subdiagr…

YOLO11改进-注意力-引入自调制特征聚合模块SMFA

本篇文章将介绍一个新的改进机制——SMFA&#xff08;自调制特征聚合模块&#xff09;&#xff0c;并阐述如何将其应用于YOLOv11中&#xff0c;显著提升模型性能。随着深度学习在计算机视觉中的不断进展&#xff0c;目标检测任务也在快速发展。YOLO系列模型&#xff08;You Onl…

嵌入式硬件杂谈(七)IGBT MOS管 三极管应用场景与区别

引言&#xff1a;在现代嵌入式硬件设计中&#xff0c;开关元件作为电路中的重要组成部分&#xff0c;起着至关重要的作用。三种主要的开关元件——IGBT&#xff08;绝缘栅双极型晶体管&#xff09;、MOSFET&#xff08;金属氧化物半导体场效应晶体管&#xff09;和三极管&#…

Numpy指南:解锁Python多维数组与矩阵运算(上)

文章一览 前言一、nmupy 简介和功能二、numpy 安装三、numpy基本使用3.1、ndarray 对象3.2、基础数据结构 ndarray 数组3.3、ndarray 数组定义3.4、ndarray 数组属性计算3.5、ndarray 数组创建3.5.1 通过 array 方式创建 ndarray 数组3.5.2 通过 arange 创建数组3.5.3 通过 lin…

SpringCloudAlibaba升级手册-nacos问题记录

目录 一、前言 二、升级过程 1.问题 2.原因 3.出处 4.理论解决 5.测试环境问题 6.Spring Cloud Alibaba版本对比 7. Spring Cloud Alibaba适配组件版本对比 8.降低Spring Cloud版本 9.SpringCloud与SpringBoot兼容对比表 10.naocs-client版本对比 三、最终解决 一…

MetaRename for Mac,适用于 Mac 的文件批量重命名工具

在处理大量文件时&#xff0c;为每个文件手动重命名既耗时又容易出错。对于摄影师、设计师、开发人员等需要频繁处理和整理文件的专业人士来说&#xff0c;找到一款能够简化这一过程的工具是至关重要的。MetaRename for Mac 就是这样一款旨在提高工作效率的应用程序&#xff0c…

blender中合并的模型,在threejs中显示多个mesh;blender多材质烘培成一个材质

描述&#xff1a;在blender中合并的模型导出为glb&#xff0c;在threejs中导入仍显示多个mesh&#xff0c;并不是统一的整体&#xff0c;导致需要整体高亮或者使用DragControls等不能统一控制。 原因&#xff1a;模型有多个材质&#xff0c;在blender中合并的时候&#xff0c;…

IntelliJ Idea常用快捷键详解

文章目录 IntelliJ Idea常用快捷键详解一、引言二、文本编辑与导航1、文本编辑2、代码折叠与展开 三、运行和调试四、代码编辑1、代码补全 五、重构与优化1、重构 六、使用示例代码注释示例代码补全示例 七、总结 IntelliJ Idea常用快捷键详解 一、引言 在Java开发中&#xff…