java 容器

1.java 容器都有哪些?
答案:Java提供了丰富的容器类,包括Collection接口的实现类(如List、Set等)和Map接口的实现类(如HashMap、TreeMap等),它们分别用于存储不同类型的元素和键值对。
---------------------------------------------------------------------------------------
Java 提供了许多类型的容器,包括:
​
ArrayList:可变大小的数组,提供高效的元素访问和插入。
LinkedList:双向链表,适用于频繁的插入和删除操作。
HashMap:基于哈希表的键值对存储结构,提供快速的查找和插入。
TreeMap:基于红黑树的有序键值对存储结构,按照键的排序顺序进行迭代。
HashSet:基于哈希表的无序集合,去重且提供快速的元素查找。
TreeSet:基于红黑树的有序集合,按照元素的排序顺序进行迭代。
Stack:后进先出(LIFO)的堆栈。
Queue:先进先出(FIFO)的队列。
PriorityQueue:基于优先级的队列,每次弹出的都是最高优先级的元素。
ConcurrentHashMap:线程安全的哈希表,支持高并发的插入和查询操作。
​
这些是 Java 中常用的容器,每个容器都适用于不同的场景和需求。
2.Collection 和 Collections 有什么区别?
答案:Collection是Java集合框架的根接口,定义了基本的集合操作方法,如添加、删除、遍历等。Collections是一个包含静态方法的工具类,提供了一些集合操作的实用方法,如排序、查找等。
---------------------------------------------------------------------------------------
Collection 和 Collections 是 Java 中两个不同的概念。
​
Collection 是 Java 中表示一组对象的接口。它是所有集合类的父接口,定义了集合操作的基本方法,例如添加元素、删除元素、判断元素是否存在等。Collection 接口有多个实现类,如 List、Set 和 Queue等。
​
Collections 是 Java 中的一个工具类,提供了一系列静态方法来对集合进行操作。这些方法包括对集合进行排序、搜索、反转等功能。Collections 类中的方法都是静态方法,可以直接通过类名调用。
​
简而言之,Collection 是一个接口,表示一组对象的集合,而 Collections 是一个工具类,提供各种对集合进行操作的静态方法。它们的名称虽然相似,但功能和用途不同。
3.List、Set、Map 之间的区别是什么?
答案:List是有序集合,允许存储重复元素,可以通过索引访问元素;Set是无序集合,不允许重复元素;Map是键值对的映射,每个键都唯一对应一个值。
---------------------------------------------------------------------------------------
List、Set 和 Map 是 Java 中常用的集合类型,它们之间的区别主要在以下几个方面:
​
唯一性:List 允许重复的元素,Set 不允许重复的元素,而 Map 中的键是不允许重复的,值可以重复。
​
排序:List 是有序集合,元素按照插入顺序或自定义的顺序进行排列;Set 是无序集合,元素无特定的顺序;Map 也是无序的,但键值对可以通过键进行排序。
​
数据结构:List 是基于索引的有序集合,允许通过索引访问和操作元素;Set 是集合,用于存储唯一的元素;Map 是键值对存储结构,通过唯一的键来访问值。
​
主要接口:List 实现了 Collection 接口,具有 List 特有的方法;Set 也实现了 Collection 接口,但不允许重复元素;Map 实现了 Map 接口,提供键值对操作。
​
总之,List 适合需要按照顺序访问和操作元素的场景;Set 适合需要存储唯一元素的场景;Map 适合需要通过键值对进行快速访问和检索的场景。根据具体的需求,选择适合的集合类型可以更好地满足编程任务的要求。
4.HashMap 和 Hashtable 有什么区别?
答案:HashMap是非线程安全的,允许有null键和值,效率较高;Hashtable是线程安全的,不允许有null键和值,效率相对较低。
---------------------------------------------------------------------------------------
HashMap 和 Hashtable 在功能上相似,但有几个重要的区别:
​
线程安全性:Hashtable 是线程安全的,而 HashMap 是非线程安全的。Hashtable 的方法是同步的,多个线程可以安全地同时访问一个 Hashtable 实例。而在 HashMap 中,如果多个线程同时访问并修改同一个 HashMap 实例,可能会导致数据不一致或抛出异常。
​
null 值:HashMap 允许键和值都为 null,而 Hashtable 不允许键或值为 null。如果试图在 Hashtable 中存储 null 值,会抛出 NullPointerException 异常。
​
继承关系:Hashtable 是早期 Java 类库中的一个类,继承自 Dictionary 类,而 HashMap 继承自 AbstractMap 类,并实现了 Map 接口。HashMap 提供了更丰富的功能和更灵活的用法。
​
性能:由于 Hashtable 是线程安全的,它需要在访问和修改集合时进行同步,这可能会对性能产生负面影响。而 HashMap 是非线程安全的,不需要进行额外的同步操作,可以获得更好的性能。
​
综上所述,HashMap 是较新且更常用的类,具有更好的性能和灵活性,尤其适用于非多线程环境。Hashtable 则适用于需要线程安全性的旧代码或多线程环境下的使用场景。
5.如何决定使用 HashMap 还是 TreeMap?
答案:如果需要无序、高效的键值对存储,可使用HashMap;如果需要按键有序存储,可使用TreeMap,它会根据键的自然顺序或指定的比较器进行排序。
---------------------------------------------------------------------------------------
使用 HashMap 还是 TreeMap 取决于你对数据的需求和使用场景。
​
排序需求:如果你需要对键进行自然排序或自定义排序,则 TreeMap 是更好的选择。TreeMap 会根据键的排序规则保持有序状态,这使得它在需要按键排序遍历或范围查询的场景下非常有用。
​
插入和查找效率:HashMap 在插入和查找操作上通常比 TreeMap 更高效。HashMap 使用哈希算法来确定存储和检索元素的位置,因此具有常数时间复杂度(O(1))的性能。而 TreeMap 通过红黑树实现有序性,并具有对数时间复杂度(O(logN))的插入、查找和删除操作。
​
内存占用:由于 TreeMap 需要存储额外的排序信息,它通常比 HashMap 占用更多的内存空间。如果内存限制是一个重要考虑因素,HashMap 可能更适合。
​
迭代顺序:HashMap 的迭代顺序是不确定的,而 TreeMap 的迭代顺序是按照键的升序进行的。因此,如果你需要按照键的顺序进行迭代,TreeMap 是更合适的选择。
​
综上所述,如果你需要排序、有序遍历或范围查询等功能,则选择 TreeMap。如果你更关注插入和查找的效率,并且不需要保持元素的有序性,则选择 HashMap。
6.说一下 HashMap 的实现原理?
答案:HashMap基于哈希表实现,内部使用一个数组来存储Entry对象,通过键的哈希码确定数组位置,当多个键映射到同一个位置时,使用链表或红黑树解决冲突。
---------------------------------------------------------------------------------------
HashMap 的实现原理主要涉及以下几个方面:
​
哈希函数:HashMap 使用哈希函数将键映射到存储桶(Bucket)的索引上。哈希函数的目标是将键的分布尽可能均匀地映射到不同的桶,以减少哈希冲突。
​
存储桶数组:HashMap 内部维护了一个存储桶数组,存储实际的键值对数据。存储桶数组的长度一般是 2 的幂次方,这样可以通过位运算来加快桶的定位。
​
链表/红黑树:当多个不同的键经过哈希函数计算得到的索引相同时,它们会被存储在同一个桶中。为了解决哈希冲突,每个桶都以链表的形式存储键值对。当链表长度超过一定阈值(默认为 8)时,链表会转换为红黑树,以提高查找的效率。
​
put 操作:当调用 put 方法插入键值对时,HashMap 首先根据键的哈希值计算出索引的位置,然后在对应的桶中进行查找。如果存在相同的键,则更新对应的值;如果不存在相同的键,则创建新的节点并插入到链表或红黑树的头部。
​
get 操作:当调用 get 方法获取值时,HashMap 会先根据键的哈希值计算出索引的位置,然后在对应的桶中进行查找。如果存在相同的键,则返回对应的值;如果不存在相同的键,则返回 null。
​
扩容机制:当存储桶中的元素数量超过了扩容阈值(默认为数组长度的 0.75 倍),HashMap 会自动进行扩容操作。扩容会新建一个容量更大的存储桶数组,并重新计算原有元素的位置,从而减少桶中元素的数量,降低哈希冲突的概率。
​
总之,HashMap 通过哈希函数、存储桶数组和链表/红黑树的组合来实现快速的键值对的存储和查找。合理的哈希函数可以减少冲突,桶的选择和链表长度的限制可以提高性能,在需要时进行扩容以保持较低的哈希冲突率。
7.说一下 HashSet 的实现原理?
答案:HashSet基于HashMap实现,它实际上是在HashMap的键部分存储元素,而值部分存储一个常量。
---------------------------------------------------------------------------------------
HashSet 是基于 HashMap 实现的,它主要涉及以下几个方面:
​
内部存储:HashSet 内部维护了一个 HashMap,其中键和值都是要存储的元素,而值则是一个常量对象(如: new Object()),因为 HashSet 不关心值的具体内容,只需要利用 HashMap 的键唯一且不重复的特点即可。
​
添加元素:当调用 add 方法将元素添加到 HashSet 中时,HashSet 会将元素作为键和一个常量值对象(如:new Object())将其添加到内部的 HashMap 中。由于 HashMap 是不允许重复键的,所以当添加一个已经存在的元素时,其键会被覆盖,但值不会被覆盖,因此 HashSet 中只会保留一个元素。
​
删除元素:当调用 remove 方法删除元素时,HashSet 会将元素作为键从内部的 HashMap 中删除即可。
​
判断元素是否在集合中存在:当调用 contains 方法判断元素是否存在于 HashSet 中时,HashSet 会使用元素作为键,针对内部 HashMap 调用 get 方法判断是否存在对应键的值。如果返回了一个非空值,则表明元素存在于 HashSet 中。
​
遍历元素:HashSet 可以通过迭代器或增强 for 循环来遍历集合中的元素。HashSet 的迭代器返回的是内部 HashMap 中的键,因此可以通过迭代器或增强 for 循环来依次访问 HashSet 中的元素。
​
总之,HashSet 的实现原理是基于 HashMap 实现的。在内部维护的 HashMap 中,HashSet 将要存储的元素作为键,将一个常量对象作为值,利用 HashMap 的键唯一且不重复的特点,来实现元素的去重和快速访问。从增删改查的角度看,HashSet 的实现原理与 HashMap 类似。
8.ArrayList 和 LinkedList 的区别是什么?
答案:ArrayList是基于动态数组实现,通过索引访问元素速度快,插入和删除元素较慢;LinkedList是基于双向链表实现,插入和删除元素速度快,但访问元素较慢。
---------------------------------------------------------------------------------------
ArrayList 和 LinkedList 是 Java 中两种常见的集合实现方式,它们在实现和使用上有以下几个区别:
​
数据结构:ArrayList 底层使用动态数组(Array)实现,而 LinkedList 使用双向链表(Doubly Linked List)实现。
​
内存占用:ArrayList 在内存占用上比 LinkedList 更高。ArrayList 需要预先分配一定大小的连续内存空间,而 LinkedList 的每个元素都包含一个指向前后节点的指针,因此 LinkedList 需要额外的内存来存储这些指针。
​
插入和删除操作:LinkedList 在插入和删除操作上比 ArrayList 更高效。由于 LinkedList 的底层是链表结构,插入和删除元素只需要修改指针的指向,而不需要像 ArrayList 那样进行数组的位移操作。
​
随机访问效率:ArrayList 在随机访问(根据索引或位置查找元素)上比 LinkedList 更高效。ArrayList 的底层是动态数组,通过索引可以直接访问到指定位置的元素,而 LinkedList 需要从头或尾开始遍历链表,直到找到目标位置。
​
内部迭代器和迭代器的性能:ArrayList 的内部迭代器(使用增强 for 循环)性能更好,因为 ArrayList 的内部实现是连续的数组,可以直接通过下标来访问元素,而 LinkedList 的内部迭代器(使用迭代器)需要遍历整个链表。
​
综上所述,如果你需要快速随机访问元素或对集合进行频繁的插入和删除操作,选择 ArrayList 更合适。而如果需要频繁的插入和删除操作,插入和删除的效率更重要,选择 LinkedList 更合适。  
9.如何实现数组和 List 之间的转换?
答案:可以使用Arrays.asList()方法将数组转换为List,或者使用ArrayList的构造函数将List转换为数组。
---------------------------------------------------------------------------------------
Java 中的数组和 List 是两种不同的数据类型,可以通过以下方法进行转换:
​
数组转 List:可以使用 Arrays 类的 asList() 方法或者手动遍历数组来完成。例如:
​
// 使用 asList() 方法将数组转化为 List
Integer[] arr = {1, 2, 3};
List<Integer> list1 = Arrays.asList(arr);
​
// 手动遍历数组方式将数组转化为 List
List<Integer> list2 = new ArrayList<>();
for (Integer i : arr) {
    list2.add(i);
}
注意,使用 asList() 方法转换得到的 List 是 Arrays 类的内部类 ArrayList,是一个固定长度的列表,不支持插入和删除操作。
​
List 转数组:可以使用集合类的 toArray() 方法或者使用 Java 8 的流式 API 来完成。例如:
​
// 使用 toArray() 方法将 List 转化为数组
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Integer[] arr1 = list.toArray(new Integer[list.size()]);
​
// 使用流式 API 将 List 转为数组
Integer[] arr2 = list.stream().toArray(Integer[]::new);
需要注意的是,如果集合中包含了基本数据类型(如 int、double 等),则需要使用对应的包装类(如 Integer、Double 等)来定义数组或集合。另外,转换后得到的数组是一个新的数组副本,对数组的修改不会影响到原集合。
​
需要注意的是,由于数组和 List 的底层实现方式不同,因此在进行数据的转换时可能会涉及到一些性能和内存问题,需要根据具体情况选择合适的方式进行转换。
10.ArrayList 和 Vector 的区别是什么?
答案:ArrayList是非线程安全的,因此在高并发环境下性能较好;Vector是线程安全的,通过锁来保证线程安全,因此性能相对较低。
---------------------------------------------------------------------------------------
ArrayList 和 Vector 是 Java 中两种相似的动态数组实现方式,它们在实现和使用上有以下几个区别:
​
线程安全性:Vector 是线程安全的,而 ArrayList 不是。Vector 的每个方法都是同步的(synchronized),可以在多线程环境下安全使用,但是会降低性能。ArrayList 没有对方法进行同步处理,因此在多线程环境下使用时需要自行进行同步处理。
​
扩容方式:Vector 和 ArrayList 在扩容方式上有差异。当元素数量超过初始容量时,Vector 会自动增长为之前容量的两倍,而 ArrayList 则增长为之前容量的 1.5 倍。
​
初始容量增长:Vector 的初始容量默认为 10,并且可以通过构造函数进行指定。ArrayList 的初始容量为 10,但也可以通过构造函数进行指定。两者的初始容量都可以根据需要自行调整。
​
历史遗留原因:Vector 是 JDK 1.0 引入的集合类,在后续的 JDK 版本中出现了 ArrayList。由于 Vector 的同步机制对性能影响较大,在单线程环境下使用 ArrayList 是更常见的选择。
​
综上所述,如果在多线程环境下需要使用动态数组,可以选择 Vector 以实现线程安全。然而,如果在单线程环境下,并且对性能较为敏感,可以选择 ArrayList 以获得更好的性能。
11.Array 和 ArrayList 有何区别?
答案:Array是固定长度的,元素类型可以是基本类型,创建后大小不可改变;ArrayList是可变长度的,只能存储对象,可以动态添加和删除元素。
---------------------------------------------------------------------------------------
Array 和 ArrayList 是两种不同的数据类型,它们在实现和使用上有以下几个区别:
​
类型:Array 是基本数据类型的连续内存块,长度固定,只能存储相同类型的元素。而 ArrayList 是 Java 集合框架中的一个类,使用动态数组实现,长度可以动态增长,可以存储任意类型的元素。
​
长度:Array 的长度是固定的,一旦创建后无法改变。如果需要存储更多的元素,需要创建一个新的数组,并将原数组的元素复制到新数组中。而 ArrayList 的长度是可变的,在需要时可以自动增长或缩小。
​
功能和灵活性:ArrayList 提供了丰富的方法和操作,如添加、删除、查找、遍历等。它提供了方便的方法来操作集合中的元素。而 Array 的功能相对较简单,需要手动编写代码来实现对数组的操作。
​
类型安全性:Array 在编译时能够检查元素类型的一致性,因为数组的类型是在创建时确定的。而 ArrayList 是一个泛型类,可以指定存储的元素类型,编译器可以进行类型检查来确保类型安全。
​
迭代器和下标操作:ArrayList 提供了方便的迭代器和下标操作来访问和操作集合中的元素。而 Array 只能通过下标操作来访问元素,没有内置的迭代器。
​
综上所述,Array 是一种传统的静态数组,长度固定,对类型有限制,操作相对简单。而 ArrayList 是动态数组,长度可变,提供了多种方便的操作方法和灵活性,适用于需要频繁动态调整大小的场景。选择使用哪种类型取决于具体的需求和使用场景。
12.在 Queue 中 poll()和 remove()有什么区别?
答案:poll()方法从队列头部获取并删除元素,如果队列为空则返回null;remove()方法从队列头部获取并删除元素,如果队列为空会抛出NoSuchElementException异常。
---------------------------------------------------------------------------------------
Queue 是 Java 提供的队列接口,提供了许多与队列的基本操作相关的方法,包括 poll() 和 remove(),它们之间的区别如下:
​
返回值:当队列为空时,调用 poll() 方法会返回 null,而调用 remove() 方法则会抛出 NoSuchElementException 异常。
​
行为:当队列非空时,poll() 方法会移除队列的头部元素并将其返回,如果队列为空则返回 null。而 remove() 方法也会移除队列的头部元素并将其返回,但是如果队列为空则会抛出 NoSuchElementException 异常。
​
因此,如果要从队列中删除元素并返回其值,可以使用 poll() 方法。如果确信队列非空并且需要删除元素,则可以使用 remove() 方法。
​
需要注意的是,Queue 是一个接口,它有多个实现类,如 LinkedList 和 ArrayDeque。对于不同的实现类,它们的行为有些许差异。因此,在使用 Queue 的时候,需要仔细查看具体实现类的文档说明,并根据实际情况选择恰当的方法来操作队列。
13.哪些集合类是线程安全的?
答案:Vector、Hashtable、Collections类的synchronizedXxx方法生成的集合,以及ConcurrentHashMap等集合类是线程安全的。
---------------------------------------------------------------------------------------
Java 集合框架中的大多数集合类都不是线程安全的,这意味着它们在多线程环境中使用时可能出现并发访问的问题。然而,Java 提供了一些线程安全的集合类,可以在多线程环境中安全使用。以下是一些常见的线程安全的集合类:
​
ConcurrentHashMap:线程安全的哈希表实现,适用于高并发环境下的读写操作。
​
CopyOnWriteArrayList:线程安全的动态数组,适用于多线程环境下对集合进行遍历操作的场景。
​
ConcurrentLinkedQueue:线程安全的链表队列实现,适用于高并发环境下的队列操作。
​
ConcurrentSkipListMap 和 ConcurrentSkipListSet:线程安全的跳表实现的有序集合类和有序映射类。
​
BlockingQueue:是一个接口,定义了阻塞操作的队列,具体实现类如 ArrayBlockingQueue、LinkedBlockingQueue 等都是线程安全的。
​
除了以上列举的线程安全集合类,Java 还提供了一些同步工具类来解决多线程并发访问的问题,如 Collections 类中的 synchronized 系列方法和各种并发锁类(如 ReentrantLock)。
​
需要注意的是,虽然这些集合类在设计上是线程安全的,但在实际使用时还是需要根据具体的应用场景和并发需求进行适当的同步控制,以保证线程安全性。
14.迭代器 Iterator 是什么?
答案:迭代器是一种用于遍历集合元素的接口,提供了统一的遍历方式,使得遍历过程更加简洁和灵活。
---------------------------------------------------------------------------------------
迭代器(Iterator)是一种用来遍历集合(如列表、数组、集合等)元素的对象。它提供了一种统一的方式来访问集合中的元素,而不需要暴露集合的内部结构。
​
迭代器具有以下几个重要的特点:
迭代器可以按序访问集合中的元素,而不需要事先知道集合的大小。
迭代器提供了在遍历过程中检索和移除元素的方法。
迭代器允许只读访问,也允许修改集合中的元素。
迭代器可以通过逐个获取元素,而不需要一次性加载整个集合到内存中。
在使用迭代器时,通常会使用两个基本方法:hasNext() 和 next()。hasNext() 用于检查迭代器中是否还有下一个元素,而 next() 用于获取迭代器中的下一个元素。
​
迭代器的使用大大简化了对集合元素的遍历操作,让代码更加简洁、灵活和易于理解。在许多编程语言中都内置了对迭代器的支持,并提供了相关的工具类和方法来操作集合。
15.Iterator 怎么使用?有什么特点?
答案:通过调用集合的iterator()方法获取迭代器对象,然后使用hasNext()判断是否有下一个元素,使用next()获取下一个元素。迭代器的特点是只能单向遍历,不支持修改操作。
---------------------------------------------------------------------------------------
使用迭代器(Iterator)可以按序遍历集合中的元素。下面是使用迭代器的一般步骤:
​
获取集合的迭代器对象:通过调用集合对象的 iterator() 方法来获取迭代器对象。这个方法通常被集合类实现,并返回一个实现了迭代器接口的对象。
​
使用迭代器进行遍历:通过调用迭代器对象的 hasNext() 方法来检查是否还有下一个元素。如果有,则调用 next() 方法来获取下一个元素。重复这个过程直到遍历完集合中的所有元素。
​
下面是使用 Java 语言的示例代码,展示了如何使用迭代器来遍历一个 ArrayList(动态数组):
​
import java.util.ArrayList;
import java.util.Iterator;
​
public class IteratorExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Orange");
​
        Iterator<String> iterator = list.iterator(); // 获取迭代器对象
​
        while (iterator.hasNext()) { // 检查是否还有下一个元素
            String element = iterator.next(); // 获取下一个元素
            System.out.println(element);
        }
    }
}
这个示例会输出以下结果:
Apple
Banana
Orange
    
迭代器的一些特点如下:
    
1.迭代器提供了一种统一的访问方式,无论集合的类型如何,都可以使用相同的方式进行遍历。
2.使用迭代器进行遍历时,不需要关心集合的内部结构,只需要关注如何获取和处理元素。
3.迭代器允许在遍历过程中删除或替换元素,而不会导致遍历错误。
4.迭代器通常是单向的,即只能从前往后遍历,不支持逆向遍历。如果需要逆向遍历,可以先将集合转换为数组再使用索5.引进行遍历。
6.当集合的内容发生变化时,迭代器可能会抛出 ConcurrentModificationException 异常。
因此,在遍历过程中应尽量避免修改集合的结构。
16.Iterator 和 ListIterator 有什么区别?
答案:Iterator用于遍历集合,只能单向遍历,不支持修改操作;ListIterator是Iterator的扩展,支持双向遍历,还可以在遍历过程中修改集合。
---------------------------------------------------------------------------------------
Iterator 和 ListIterator 都是 Java 中用来遍历集合(如 List、Set 等)的接口,它们都提供了相似的遍历方法,但也有一些区别。
​
主要的区别在于 ListIterator 接口具有比 Iterator 更多的遍历功能。以下是 ListIterator 相对于 Iterator 的一些区别:
​
ListIterator 比 Iterator 多了一个 previous() 方法,可以支持反向遍历集合。
​
ListIterator 可以使用 set() 方法更新集合中遍历到的元素的值,而 Iterator 没有提供这种功能。
​
ListIterator 可以插入和删除元素,而 Iterator 只能删除元素。ListIterator 提供了三个插入元素的方法:add()、set() 和 previous(),而 Iterator 只有一个 remove() 方法。
​
因此,如果在遍历一个列表时需要更复杂的遍历功能,比如插入、删除或者反向遍历,那么应该使用 ListIterator 接口。如果只需简单地遍历列表并访问元素,则使用 Iterator 接口即可。
​
下面是一个简单的示例程序,展示了如何使用 ListIterator 接口来遍历和更新列表中的元素:
​
import java.util.ArrayList;
import java.util.ListIterator;
​
public class ListIteratorExample {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Orange");
​
        ListIterator<String> listIterator = list.listIterator();
​
        while (listIterator.hasNext()) {
            String element = listIterator.next();
            System.out.println(element);
            if (element.equals("Banana")) {
                listIterator.set("Grapes"); // 替换当前元素
                listIterator.add("Cherry"); // 在当前位置后插入一个元素
            }
        }
​
        System.out.println("After traversal and modification:");
        for (String element : list) {
            System.out.println(element);
        }
    }
}
输出结果为:
​
Apple
Banana
Orange
After traversal and modification:
Apple
Grapes
Cherry
Orange
17.怎么确保一个集合不能被修改?
答案:可以使用Collections.unmodifiableXxx方法,将集合转换为不可修改的视图,尝试修改会抛出UnsupportedOperationException异常。
--------------------------------------------------------------------------------------
要确保一个集合不能被修改,可以使用 Java 中的不可变集合(Immutable Collection)。
​
不可变集合是指在创建后不能被修改的集合。它们提供了只读的访问权限,并且不允许添加、删除或修改其中的元素。这种特性确保了集合的数据不会被意外地修改,提高了代码的安全性和可靠性。
​
Java 提供了一些不可变集合的实现类,如 java.util.Collections 中的 unmodifiableXXX() 方法可以创建不可变的列表、集合和映射。
​
下面是一个示例演示如何创建一个不可变的列表:
​
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
​
public class ImmutableCollectionExample {
    public static void main(String[] args) {
        ArrayList<String> mutableList = new ArrayList<>();
        mutableList.add("Apple");
        mutableList.add("Banana");
        mutableList.add("Orange");
​
        List<String> immutableList = Collections.unmodifiableList(mutableList);
​
        System.out.println("Before modification:");
        for (String element : immutableList) {
            System.out.println(element);
        }
​
        // 修改原始列表
        mutableList.add("Grapes");
​
        System.out.println("After modification:");
        for (String element : immutableList) {
            System.out.println(element);
        }
    }
}
输出结果为:
​
Before modification:
Apple
Banana
Orange
After modification:
Apple
Banana
Orange
如上所示,通过使用 Collections.unmodifiableList() 方法,我们创建了一个不可变的列表 immutableList。尝试修改原始列表 mutableList 并不会影响到不可变列表。
​
需要注意的是,虽然不可变集合本身不能被修改,但如果不可变集合的元素是可变的对象,则这些对象的状态可能仍然可以被修改。因此,在确保集合的不可变性时,确保集合中的元素也是不可变的是很重要的
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值