Java 中的集合是什么?
在 Java 中,集合是一个框架,它提供了用于存储和操作对象集合的体系结构。在 JDK 1.2 中,创建了一个名为“集合框架”的新框架,其中包含所有集合类和接口。
Java中的集合能够执行任何数据操作,例如搜索、排序、插入、操作和删除。
Java 中的单个对象单元称为集合。Java 集合类的两个基本“根”接口是 Collection 接口 (java.util.Collection) 和 Map 接口 (java.util.Map)。Java 集合框架中提供了许多接口(Set、List、Queue、Deque)和类(ArrayList、Vector、LinkedList、PriorityQueue、HashSet、LinkedHashSet、TreeSet)。
对集合框架的需求:-
在引入集合框架(或 JDK 1.2)之前,聚合 Java 对象(或集合)的标准技术是数组、向量或哈希表。所有这些集合都没有通用接口。结果,虽然所有集合的基本目标是相同的,但它们的实现是独立指定的,它们之间没有关联。此外,用户发现很难记住每个集合类中包含的所有各种方法、语法和构造函数。
1. java中的Array和Collection有什么区别?
Array 和 Collection 在存储对象引用和操作数据方面是等价的,但它们在许多方面有所不同。以下是数组和集合之间的主要区别:
Array | Collection |
---|---|
数组有一个固定的大小,这意味着一旦我们构建了一个,我们就不能改变它来满足我们的需要。 | 收藏品是自然生长的,可以定制以满足我们的需求。我们可以根据我们的要求改变它的大小。 |
在性能方面,Arrays 是 Collection 的首选。 | 考虑到性能,Collection 不优于 Arrays。 |
只有同类数据类型元素可以存储在数组中。 | 同质和异质组件都可以存储在集合中。 |
因为数组没有底层数据结构,所以没有现成的方法支持。 | 任何集合类都是建立在标准数据结构之上的,因此对于每一个需求作为性能都有现成的方法支持。这些方法可以直接使用,我们不负责它们的实现。 |
对象和原语都可以存储在数组中。 | 只有对象类型可以存储在集合中。 |
在内存方面,数组不优于集合。 | 考虑到内存,Collection 优于 Arrays。 |
2. 区分 Collection 和 Java 上下文中的集合。
Collection:在 java.util.package 中有一个叫做集合的接口。它用于将单独对象的集合表示为单个实体。它相当于 C++ 编程语言中的容器。集合框架的根接口称为集合。它有许多类和接口,用于将单个对象的集合表示为一个单元。采集接口的关键子接口有List、Set、Queue。虽然 map 接口是 Java 集合框架的一部分,但它不继承接口的集合。Collection 接口最重要的函数是 add()、remove()、clear()、size() 和 contains()。
Collections:java.util.package 有一个名为 Collections 的实用程序类。它定义了用于处理集合的各种实用方法,例如排序和搜索。所有方法都是静态的。这些技术为开发人员提供了急需的便利,使他们能够更成功地与 Collection Framework 交互。它提供了类似 sort() 的方法来按正常排序顺序对集合元素进行排序,并提供 min() 和 max() 来分别获取集合元素中的最小值和最大值。
Collection | Collections |
---|---|
它用于将单独对象的集合表示为单个实体。 | 它定义了许多处理集合的有用方法。 |
它是一个接口。 | 它是一个实用程序类。 |
从 Java 8 开始,Collection 是一个带有静态函数的接口。抽象和默认方法也可以在接口中找到。 | 它只有静态方法。 |
3. 解释 Java 中 Collection 框架的层次结构。
整个集合框架层次结构由四个基本接口组成:Collection、List、Set、Map,以及两个用于排序的特定接口,称为 SortedSet 和 SortedMap。java.util 包包含集合框架的所有接口和类。下图描述了 Java 集合结构。
这里,e表示扩展,i表示实现
- Extends:关键字extends用于在两个类和两个接口之间创建继承。
- Implements:关键字 implements 用于创建跨类和接口的继承。
4、Collection框架有什么优势?
以下是 Collection 框架的优点:-
一致的 API:API 有一组核心接口,如 Collection、Set、List 或 Map,实现这些接口的所有类(ArrayList、LinkedList、Vector 等)都有一些通用的方法集。
减少编程工作量:程序员不必担心 Collection 的设计,而可以专注于如何在他的程序中最好地使用它。结果,面向对象程序设计(即抽象)的基本原理得到了成功的应用。
通过提供有用的数据结构和算法的高性能实现来提高程序速度和质量,因为程序员不必担心在这种情况下某个数据结构的最佳实现。他们可以简单地使用最佳实现来显着提高程序的性能。
5. 解释 Collection 框架中使用的各种接口。
集合框架有几个接口,每个接口用于存储不同类型的数据。下面列出了框架中包含的接口。
1. 可迭代接口:这是集合框架的主要接口。可迭代接口由集合接口扩展。因此,所有的接口和类都默认实现了这个接口。这个接口的主要目的是为集合提供一个迭代器。结果,这个接口只有一个抽象方法,迭代器。
2. 集合接口:集合框架的类实现了这个接口,扩展了可迭代接口。该接口涵盖了每个集合具有的所有基本方法,例如向集合中添加数据、从集合中删除数据、清除数据等。所有这些方法都包含在此接口中,因为所有类都使用它们,而不管它们的实现风格如何。此外,在此接口中包含这些方法可确保方法名称在所有集合中保持一致。总之,我们可以得出结论,这个接口为集合类的实现奠定了基础。
3.列表接口:集合接口有一个子接口,称为列表接口。该接口专门用于列表数据,我们可以将所有对象存储在有序集合中。这也允许存在冗余数据。ArrayList、Vector、Stack 等各种类都实现了这个列表接口。我们可以用这些类中的任何一个创建一个列表对象,因为它们都实现了列表。
4.队列接口:队列接口,顾名思义,遵循现实世界队列行的FIFO(先进先出)顺序。该接口用于存储元素顺序很重要的所有元素。例如,当我们尝试在商店购物时,账单是按照先到先得的原则发放的。结果,请求排在第一位的个人首先收到账单。PriorityQueue、Deque、ArrayDeque 和其他类可用。因为所有这些子类都实现了队列,所以我们可以使用它们中的任何一个来创建队列对象。
5. Deque Interface:与队列数据结构略有不同。双端队列,也称为双端队列,是一种数据结构,可以从两端添加和删除元素。该接口扩展了队列接口。ArrayDeque 是实现这个接口的类。因为这个类实现了双端队列,我们可以用它来创建双端队列对象。
6. 集合接口:集合是一组无序的对象,其中不能保留重复值。当我们想要避免重复事物并只保留唯一的事物时,就会使用此集合。HashSet、TreeSet、LinkedHashSet 等各种类都实现了这个集合接口。我们可以用这些类中的任何一个创建一个集合对象,因为它们都实现了集合。
7. 排序集界面:该界面在外观上类似于集合界面。唯一的区别是这个接口提供了额外的方法来维护元素的顺序。排序集接口是集合接口的扩展,用于管理排序数据。TreeSet 就是实现这个接口的类。我们可以使用这个类创建一个 SortedSet 对象,因为它实现了 SortedSet 接口。
6、ArrayList和LinkedList的区别。
数组列表 | 链表 |
---|---|
此类的元素存储在动态数组中。由于添加了泛型,该类现在支持存储所有类型的对象。 | 此类的元素存储在双向链表中。这个类和 ArrayList 一样,允许存储任何类型的对象。 |
List 接口由该类实现。结果,这用作列表。 | List 和 Deque 接口都由这个类实现。因此,它既可以用作列表,也可以用作双端队列。 |
由于内部实现,操作 ArrayList 需要更长的时间。在内部,每当我们删除一个元素时,都会扫描数组并移动内存位。 | 因为在双向链表中没有改变内存位的概念,所以操作它比操作 ArrayList 花费的时间更少。遍历列表后,参考链接发生变化。 |
当应用程序需要数据存储和访问时,此类更有用。 | 当应用程序需要数据操作时,此类更有用。 |
7、java中ArrayList和Vector的区别。
以下是 java 中 ArrayList 和 Vector 之间的区别:
-
Vector是同步的,也就是说一次只能有一个线程访问代码,而ArrayList是不同步的,就是多个线程可以同时对ArrayList进行操作。例如,在多线程系统中,如果一个线程正在执行添加操作,则另一个线程可能正在执行删除操作。
如果多个线程同时访问 ArrayList,我们必须同步从根本上更新列表的代码或启用简单的元素更改。从列表中添加或删除元素称为结构更改。更改现有元素的值不是结构更改。
- 数据增长:ArrayList 和 Vector 都动态扩展和收缩以最大限度地利用存储空间,但它们的方式不同。如果数组中的元素数量超过其限制,ArrayList 会增加当前数组大小的 50%,而 vector 会增加 100%,从而使当前数组大小增加一倍。
- 性能:ArrayList 比向量操作快,因为它是非同步的,但向量操作较慢,因为它们是同步的(线程安全的)。当一个线程在一个向量上工作时,它会在它上面获得一个锁,要求任何其他在它上面工作的线程等待直到锁被释放。
- Vector 可以使用 Enumeration 和 Iterator 遍历其元素,而 ArrayList 只能使用 Iterator 遍历。
8. 区分Java中的List和Set。
List 接口用于跟踪有序集合。它是 Collection 的子接口。它是允许存储重复值的有序对象集合。插入顺序保存在一个列表中,它支持位置访问和元素插入。
set 接口是 java.util 包的一部分,并扩展了 Collection 接口。它是一个无序的对象集合,其中不能存储重复值。它是使用数学集的接口。该接口继承了 Collection 接口的方法,并添加了防止插入重复元素的功能。
Set | List |
---|---|
这是一个无序的序列。 | 它是一个有序的序列。 |
Set 中不允许有重复的元素。 | 列表中允许重复元素 |
不允许从某个位置访问项目。 | 可以根据元素的位置访问元素。 |
一个空元素只能存储一次。 | 可以存储多个空元素。 |
9. 区分Java中的Iterator和ListIterator。
在 Java 的 Collection 框架中,迭代器用于一个一个地获取元素。它可以用于任何类型的 Collection 对象。我们可以使用迭代器执行读取和删除操作。当我们想要迭代所有 Collection 框架实现的接口中的元素时,必须使用迭代器,例如 Set、List、Queue 和 Deque,以及所有 Map 接口实现的类。整个集合框架唯一可访问的游标是迭代器。
ListIterator 仅对实现 List 集合的类有用,例如数组列表和链表。它可以双向迭代。当我们希望枚举 List 元素时,我们必须使用 ListIterator。此游标具有比迭代器更多的方法和功能。
迭代器 Iterator | 列表迭代器 ListIterator |
---|---|
只能向前遍历 Collection 中的组件。 | 在向前和向后的方向上,都可以遍历 Collection 中的组件。 |
迭代器不能用于获取索引。 | 它提供了在遍历 List 时随时获取元素索引的方法,例如 next Index() 和 previous Index()。 |
它有助于遍历 Maps、Lists 和 Sets。 | 只有 List 可以被遍历,而不是其他两个。 |
由于无法添加元素,因此会引发并发修改异常。 | 您可以随时将元素快速添加到集合中。 |
next()、remove() 和 has Next 是 Iterator 的一些函数 ()。 | next()、previous()、has Next()、has Previous() 和 add() 是 List Iterator 的一些方法 |
10.区分HashSet和TreeSet。什么时候你更喜欢 TreeSet 而不是 HashSet?
以下是 HashSet 和 TreeSet 之间的区别:-
- 内部实施和速度
- HashSet:对于搜索、插入和删除操作,平均需要恒定的时间。TreeSet 比 HashSet 慢。哈希表用于实现 HashSet。
- TreeSet:对于查找、插入和删除,TreeSet 取 O(Log n),高于 HashSet。另一方面,TreeSet 保留有序数据。Higher()(返回最低高的元素)、floor()、ceiling() 等操作也受支持。在 TreeSet 中,这些操作同样是 O(Log n),而 HashSet 没有实现它们。自平衡二叉搜索树用于实现 TreeSet(红黑树)。在 Java 中,TreeSet 由 TreeMap 支持。
- 存储元素
的方式 HashSet 的元素是无序的。在 Java 中,TreeSet 类以由 Comparable 或 Comparator 方法定义的排序顺序保存对象。默认情况下,TreeSet 组件按升序排序。它有很多处理有序集合的方法,包括first()、last()、headSet()、tailSet()等。 - **允许 Null 值 **
在 HashSet 中允许 Null 对象。TreeSet 不允许空对象并引发 NullPointerException。这是因为 TreeSet 使用 compareTo() 方法比较键,该方法抛出 java.lang。空指针异常。 - 比较
HashSet 比较 Set 中的两个对象并使用 equals() 方法检测重复项。出于同样的目的,TreeSet 使用了 compareTo() 方法。如果 equals() 和 compareTo() 不一致,即如果 equals() 对两个相等的对象返回 true 但 compareTo() 返回零,则 Set 接口的约定将被破坏,允许在 TreeSet 等 Set 实现中重复。
以下是 TreeSet 优于 HashSet 的情况:
- 需要排序的唯一元素,而不是唯一元素。TreeSet 返回一个始终按升序排列的排序列表。
- TreeSet 的局部性高于 HashSet。如果两个条目按顺序靠近,TreeSet 将它们放在相同的数据结构中,因此放在内存中,但 HashSet 将条目分散在内存中,而不管它们链接到的键是什么。
- 为了对组件进行排序,TreeSet 采用了红黑树方法。如果您需要定期进行读/写操作,TreeSet 是一个很棒的解决方案。
11. 可以在 TreeSet 或 HashSet 中添加 null 元素吗?
我们可以在 HashSet 中添加 null 元素,但不能在 TreeSet 中添加 null 元素。原因是 TreeSet 使用 compareTo() 方法进行比较,当遇到空元素时会抛出 NullPointerException。
12. Java 中的优先级队列是什么?
如果要按优先级顺序处理对象,则使用 PriorityQueue。众所周知,队列遵循先进先出方法,但是,有时必须按优先级顺序处理队列的组件,这就是 PriorityQueue 发挥作用的地方。优先级堆是 PriorityQueue 的基础。优先级队列的成员根据自然顺序或队列构建时提供的比较器进行排序。
Serializable、Iterable
13. 使用 Java 集合时有哪些最佳实践?
以下是使用 Java 集合时的一些最佳实践:
- 选择合适的集合:
在我们使用集合之前,我们必须为我们正在寻求解决的问题选择最相关的集合。如果我们选错了,我们的程序可能仍然可以运行,但效率会很低。另一方面,如果我们选择了正确的,我们的解决方案会简单很多,我们的程序会运行得更快。 - 指定集合的初始容量:
几乎所有集合类都包含一个重载的构造函数,用于确定集合的初始容量。也就是说,如果我们确切地知道将要添加多少块到集合中,我们就可以在建立新实例时定义初始容量。 - 使用 isEmpty() 代替 size():
要检查集合是否为空,我们应该使用 isEmpty() 方法,而不是查找集合的大小并将其与零进行比较。这增强了代码的可读性。 - 使用迭代器遍历集合:
我们应该使用迭代器来遍历集合元素,而不是使用 for 循环。原因是如果任何其他线程在创建迭代器后尝试修改集合,迭代器可能会抛出 ConcurrentModificationException。这使我们免于错误。 - 在同步包装器上使用并发集合:
我们应该考虑在多线程应用程序中使用来自 java.util.concurrent 包的并发集合,而不是使用由 Collections.synchronizedXXX() 方法生成的同步集合。因为并发集合采用各种同步策略,例如写时复制、比较和交换和特定锁,所以它们旨在为并发应用程序提供最大性能。 - 消除未经检查的警告:
我们不应忽视来自 Java 编译器的未经检查的警告。理想的做法是摆脱任何未检查的警告。 - 偏爱泛型类型:
我们应该考虑使用泛型参数构建新方法,并将现有方法转换为使用类型参数,就像我们应该使用泛型类型一样,因为泛型方法比非泛型方法更安全、更容易使用。泛型方法还有助于创建通用且可重用的 API。
14. Java中Set和Map的区别。
Set接口由Java.util 包提供。集合接口是通过扩展集合接口建立的。我们不能向它添加相同的元素,因为它不允许我们这样做。因为它包含按排序顺序的元素,所以它不保持插入顺序。Java 中的 Set 接口用于构建数学 Set。
Map与 Set 类似,用于将对象集合存储为单个实体。键值对用于存储每个对象。因为每个值都与唯一的键相关联,所以我们可以仅使用键快速获取值。
set | map |
---|---|
它不能有重复的值。无法将相同的元素添加到集合中。每个实现 Set 接口的类中只存储唯一值。 | 不同的键可能具有相同的值。该地图具有重复的唯一键和值。 |
使用 keyset() 和 entryset() 方法,我们可以快速迭代 Set 项。 | 无法遍历地图元素。要迭代元素,我们必须将 Map 转换为 Set。 |
Set 接口不跟踪插入顺序。但是,它的某些类(例如 LinkedHashSet)保持插入顺序。 | Map 不跟踪插入序列。一些 Map 类,例如 TreeMap 和 LinkedHashMap,做同样的事情。 |
15. HashSet和HashMap的区别。
HashSet是一个不允许重复值的 Set 接口实现。要点是存储在 HashSet 中的对象必须覆盖 equals() 和 hashCode() 方法,以确保没有重复值存储在我们的集合中。
HashMap是一种映射接口实现,将键映射到值。在地图中,不允许重复键。
HashSet | HashMap |
---|---|
它实现了 Set 接口。 | 它实现了Map接口。 |
它不允许重复值。 | 键必须是唯一的,而两个不同的键可以具有相同的值。 |
添加元素时,它只需要一个对象作为参数。 | 添加条目时,它需要两个对象值,即Key和Value作为参数。 |
在内部,HashSet 使用 HashMap 来添加条目。HashSet 中的键 K 是 add(Object) 方法中提供的参数。对于 add(Object) 方法中提供的每个值,Java 分配一个虚拟值。 | 没有重复值的概念。 |
它比 HashMap 慢。 | 它比 HashSet 快。 |
它使用 add() 方法添加元素。 | 它使用 put() 方法添加数据元素。 |
16. 在基于散列的集合中负载因子的默认大小是多少?
默认负载因子大小为0.75。默认容量是通过将初始容量乘以负载系数来计算的。
17. 区分Java中的Array和ArrayList。
以下是 Java 中 Arrays 和 ArrayLists 之间的区别:
- Java 提供数组作为基本功能。ArrayList 是Java 集合系统的一个组件。因此,它用于访问数组成员,而 ArrayList 提供了一组访问和修改组件的方法。
- ArrayList 不是固定大小的数据结构,但 Array 是。创建 ArrayList 对象时,无需提供其大小。即使我们设置了最大容量,我们也可以在之后添加更多部件。
- 数组可以包含原始数据类型和类对象,具体取决于数组的定义。另一方面,ArrayList 只接受对象条目而不接受原始数据类型。请注意,当我们使用 arraylist.add(1); 时,原始 int 数据类型将转换为 Integer 对象。
- ArrayList 的成员总是引用不同内存位置的对象,因为不能为原始数据类型构造 ArrayList 结果,ArrayList 中的实际对象永远不会保存在同一个位置。对真实物品的引用保持在附近。数组是原始数组还是对象取决于数组的类型。原始类型的实际值是连续区域,而对象的分配等效于 ArrayList。
- Java ArrayList 支持许多其他操作,例如 indexOf() 和 delete()。数组不支持这些功能。
18. 如何在 Java 中将 ArrayList 设为只读?
借助 Collections.unmodifiableList() 方法,我们可以轻松地将 ArrayList 设为只读。此函数将可变的 ArrayList 作为输入,并返回 ArrayList 的只读、未修改的视图。
例子:
import java.util.*;
public class InterviewBit {
public static void main(String[] args)
throws Exception
{
try {
// creating object of ArrayList
List sample_list = new ArrayList();
sample_list.add(“practice”);
sample_list.add(“solve”);
sample_list.add(“interview”);
// displaying the initial list
System.out.println("The initial list is : "
+ sample_list);
// using unmodifiableList() method
List
read_only_list = Collections
.unmodifiableList(sample_list);
// displaying the read-only list
System.out.println("The ReadOnly ArrayList is : "
+ read_only_list);
// Trying to add an element to the read-only list
System.out.println("Trying to modify the ReadOnly ArrayList.");
read_only_list.add(“job”);
}
catch (UnsupportedOperationException e) {
System.out.println("The exception thrown is : " + e);
}
}
}
输出:
The initial list is : [practice, solve, interview]
The ReadOnly ArrayList is : [practice, solve, interview]
Trying to modify th eReadOnly ArrayList.
Exception thrown : java.lang.UnsupportedOperationException
我们可以看到,当我们尝试将元素添加到只读 ArrayList 时,我们会抛出异常。
19.区分Java上下文中的Comparable和Comparator。
Comparable | Comparator |
---|---|
Comparable 提供了一个单一的排序顺序。换句话说,我们可以按单个属性(例如 id、name 或 price)对集合进行排序。 | 比较器中提供了多个排序顺序。换句话说,我们可以根据 id、name 和 price 等不同的标准对集合进行排序。 |
为了对元素进行排序,Comparable 提供了 compareTo() 方法。 | 为了对元素进行排序,Comparator 提供了 compare() 方法。 |
它存在于 java.lang 包中。 | 它存在于 java.util 包中。 |
原类受Comparable影响,即改变了真实类。 | 原始类不受比较器的影响,即真实类不受影响。 |
Collections.sort(List) 方法可用于对 Comparable 类型列表成员进行排序。 | Collections.sort(List, Comparator) 方法可用于对 Comparator 类型的列表组件进行排序。 |
20. 你对 Java 中的 BlockingQueue 了解多少?
BlockingQueue 是一个与许多其他并发实用程序类(例如 ConcurrentHashMap、Counting Semaphore、CopyOnWriteArrayList 等)一起包含的接口。除了排队,BlockingQueue 接口通过在 BlockingQueue 已满或为空时添加阻塞来启用流控制。
试图将一个元素加入一个完整队列的线程将被阻塞,直到另一个线程通过使一个或多个元素出队或完全清除队列来清除队列。它还可以防止线程从空队列中删除,直到另一个线程插入一个项目。BlockingQueue 不接受空值。Java BlockingQueue 接口的实现是线程安全的。BlockingQueue 的方法都是原子的,并使用内部锁或其他形式的并发管理。
Java中有两种类型的BlockingQueue。它们如下:
无界队列:阻塞队列的容量将设置为整数。最大值。无界阻塞队列永远不会阻塞,因为它有可能增长到非常大的规模。随着您添加更多片段,队列的大小会增加。
例子 :
BlockingQueue unbounded_queue = new LinkedBlockingDeque();
有界队列:有界队列是第二种队列。在有界队列的情况下,队列的容量可以在创建阻塞队列时传递给构造函数。
例子:
// Creates a Blocking Queue with capacity 10
BlockingQueue bounded_queue = new LinkedBlockingDeque(10);
21. 解释故障快速和故障安全迭代器。区分它们。
如果集合的结构发生变化,Fail-Fast迭代器会立即抛出 ConcurrentModificationException。当线程遍历集合时,结构更改包括添加或删除任何元素。故障安全迭代器类包括 ArrayList Iterator 和 HashMap Iterator。快速失败迭代器使用称为 modCount 的内部指示符,每次修改集合时都会更新该指示符,以确定集合是否已在结构上进行了修改。当快速失败迭代器(通过 next() 方法)获取下一项时,它会检查 modCount 标志,如果在生成迭代器后发现 modCount 已更改,则抛出 ConcurrentModificationException。
如果在对集合进行迭代时对其进行了结构更新,则故障安全迭代器不会抛出任何异常。因为它们对集合的克隆而不是原始集合进行操作,所以它们被称为故障安全迭代器。故障安全迭代器包括 CopyOnWriteArrayList 和 ConcurrentHashMap 类。
Fail-Fast | Fail-safe |
---|---|
这些类型的迭代器不允许在迭代集合时修改集合。 | 这些类型的迭代器允许在迭代集合时修改集合。 |
如果在迭代集合时修改了集合,它会抛出 ConcurrentModificationException。 | 如果在迭代集合时修改了集合,则不会引发异常。 |
它在遍历元素时使用原始集合。 | 它在遍历它时使用原始集合的副本。 |
在这种情况下不需要额外的内存。 | 在这种情况下需要额外的内存。 |
22. RandomAccess 接口的用途是什么?命名实现此接口的集合类型。
RandomAccess 与 Serializable 和 Cloneable 接口一样,是一个标记接口。这些标记接口中没有定义任何方法。相反,他们将一个类指定为具有特定能力。
RandomAccess 接口指示给定的 java.util.List 实现是否支持随机访问。这个界面试图定义一个模糊的概念:快速是什么意思?文档中提供了一个简单的指南:如果使用 List.get() 方法重复访问比使用 Iterator.next() 方法重复访问更快,则 List 具有快速随机访问。
使用 List.get() 重复访问:
Object obj;
for (int i=0, n=list.size( ); i < n; i++)
obj = list.get(i);
使用 Iterator.next( ) 重复访问:
Object obj;
for (Iterator itr=list.iterator( ); itr.hasNext( ); )
obj = itr.next( );
23. 区分迭代器和枚举。
Iterator:因为它可以应用于任何 Collection 对象,所以它是一个通用的迭代器。我们可以使用迭代器执行读取和删除操作。它是 Enumeration 的增强版本,增加了从列表中删除元素的功能。
枚举:枚举(或枚举)是由用户定义的数据类型。它主要用于给出整数常量名称,这使程序更易于理解和维护。枚举在 Java 中(从 1.5 开始)通过枚举数据类型表示。
迭代器 Iterator | 枚举 Enumeration |
---|---|
Iterator 是一个通用游标,因为它适用于所有集合类。 | 因为它只适用于遗留类,所以枚举不是通用游标。 |
迭代器可以进行更改(例如,delete() 方法在遍历期间从 Collection 中删除元素)。 | Enumeration 接口是一个只读接口,这意味着您在遍历 Collection 元素时不能对 Collection 进行任何更改。 |
remove() 方法在 Iterator 类中可用。 | remove() 方法在枚举中不可用。 |
迭代器不是遗留接口。Iterator 可以遍历 HashMaps、LinkedLists、ArrayLists、HashSets、TreeMaps 和 TreeSets。 | 枚举是用于遍历 Hashtables 和 Vectors 的遗留接口。 |
24、Java中Properties类有什么用?属性文件有什么好处?
键值对都是属性对象中的字符串。java.util.Properties 类是 Hashtable 子类。
它可用于根据其键计算属性的值。Properties 类具有从属性文件读取和写入数据的方法。它也可以用来获取系统的属性。
属性文件的优点:
如果修改了属性文件中的信息,则不需要重新编译:如果属性文件中的任何信息发生更改,则无需重新编译 java 类。它用于跟踪需要经常更新的信息。
例子:
让我们首先创建一个名为“info.properties”的属性文件,其内容如下:
用户=成功
密码=决心
现在让我们创建一个 java 类来从属性文件中读取数据
import java.util.*;
import java.io.*;
public class Sample {
public static void main(String[] args)throws Exception{
FileReader reader = new FileReader("info.properties");
Properties obj_p = new Properties();
obj_p.load(reader);
System.out.println(obj_p.getProperty("user"));
System.out.println(obj_p.getProperty("password"));
}
}
输出:
success
determination
25. HashMap和HashTable的区别。
以下是HashMap和HashTable的区别:
- HashMap 是一种非同步数据结构。它不是线程安全的,并且在不使用同步代码的情况下不能在多个线程之间共享,而 Hashtable 是同步的。它是线程安全的,可以被多个线程使用。
- HashMap 支持一个空键和多个空值,而 Hashtable 不支持。
- 如果不需要线程同步,HashMap 通常比 HashTable 更可取。
26. 为什么HashMap允许null,而HashTable不允许null?
用作键的对象必须实现 hashCode 和 equals 方法才能成功地从 HashTable 中保存和检索对象。这些方法不能由 null 实现,因为它不是对象。HashMap是Hashtable的一个更高级和改进的变体。HashMap是在HashTable之后发明的,以克服HashTable的缺点。
27. 如何在 Java 中同步一个 ArrayList?
可以使用以下两种方式同步 ArrayList:
- 使用 Collections.synchronizedList() 方法:
对备份列表的所有访问都必须通过返回列表完成,才能执行串行访问。在遍历返回的列表时,用户手动同步至关重要。
例子:
import java.util.*;
class InterviewBit
{
public static void main (String[] args)
{
List synchronized_list =
Collections.synchronizedList(new ArrayList());
synchronized_list.add("learn");
synchronized_list.add("practice");
synchronized_list.add("solve");
synchronized_list.add("interview");
synchronized(synchronized_list)// must be declared
{
Iterator it = synchronized_list.iterator();
while (it.hasNext())
System.out.println(it.next());
}
}
}
输出:
learn
practice
solve
interview
- 使用 CopyOnWriteArrayList:
句法:
CopyOnWriteArrayList list_name = new CopyOnWriteArrayList();
在这里,创建了 ArrayList 的线程安全变体。T 代表通用。
所有可变操作(例如添加、设置、删除等)都是通过在 ArrayList 的这个线程安全变体中生成底层数组的单独副本来实现的。它通过生成 List 的第二个副本来实现线程安全,这与向量和其他集合实现线程安全的方式不同。
即使在形成迭代器后修改了 copyOnWriteArrayList,迭代器也不会引发 ConcurrentModificationException,因为迭代器正在对 ArrayList 的单独副本进行迭代,而对 ArrayList 的另一个副本进行写操作。
例子:
import java.io.*;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
class InterviewBit
{
public static void main (String[] args)
{
CopyOnWriteArrayList synchronized_list
= new CopyOnWriteArrayList();// creating a thread-safe Arraylist.
// Adding strings to the synchronized ArrayList
synchronized_list.add("learn");
synchronized_list.add("practice");
synchronized_list.add("solve");
synchronized_list.add("interview");
System.out.println("The synchronized ArrayList has the following elements :");
// Iterating on the synchronized ArrayList using an iterator.
Iterator it = synchronized_list.iterator();
while (it.hasNext())
System.out.println(it.next());
}
}
输出:
The synchronized ArrayList has the following elements :
learn
practice
solve
interview
28. 当我们在Java中有Vectors(它们是同步的)时,为什么我们需要同步的ArrayList?
以下是我们需要同步 ArrayLists 的原因,即使我们有 Vectors :
- Vector 比 ArrayList 稍慢,因为它是同步的和线程安全的。
- Vector 的功能是同步每个单独的动作。程序员的偏好是同步整个动作序列。单独的操作不太安全,并且需要更长的时间来同步。
- 向量在 Java 中被认为是过时的并且已被非正式地弃用。Vector 还基于每个操作进行同步,这几乎从未完成。大多数 Java 程序员更喜欢使用 ArrayList,因为他们几乎肯定会在需要时显式同步 arrayList。
29、为什么Map接口不扩展Collection接口,反之亦然?
如果 Map 扩展了 Collection 接口,“键值对”可以是此类 Collection 的唯一元素类型,尽管这提供了非常有限(并且不是真正有用)的 Map 抽象。您无法查询特定键对应的值,也无法在不知道它对应的值的情况下删除条目。
Maps 上的三个“Collection 查看过程”表示 Maps 可以被视为集合(键、值或对)(keySet、entrySet 和值)的事实。虽然理论上可以将 List 视为映射到项的 Map 索引,但这具有不幸的副作用,即在删除成员之前更改与 List 中的每个元素关联的 Key。这也是不能做Collection来扩展Map Interface的原因。
30. 区分Java上下文中的HashMap和TreeMap。
HashMap | TreeMap |
---|---|
Map 接口的 Java HashMap 实现基于哈希表。 | Java TreeMap 是基于Tree 结构的Map 接口实现。 |
Map、Cloneable 和 Serializable 接口由 HashMap 实现。 | NavigableMap、Cloneable 和 Serializable 接口由 TreeMap 实现。 |
因为 HashMap 不对键进行排序,所以它允许异构元素。 | 由于排序,TreeMap 允许将同质值用作键。 |
HashMap 比 TreeMap 更快,因为它为 get() 和 put() 等基本操作提供了 O(1) 的恒定时间性能。 | TreeMap 比 HashMap 慢,因为它以 O(log(n)) 的性能执行大多数操作,例如 add()、remove() 和 contains()。 |
HashMap 中允许单个空键和多个空值。 | TreeMap 不允许空键,但允许多个空值。 |
为了比较键,它使用 Object 类的 equals() 方法。它被 Map 类的 equals() 函数覆盖。 | 它使用 compareTo() 方法比较键。 |
HashMap 不跟踪任何顺序。 | 元素按时间顺序(升序)排列。 |
当我们不需要排序的键值对时,我们应该使用 HashMap。 | 当我们需要按排序(升序)顺序的键值对时,我们应该使用 TreeMap。 |
Java 收集程序
31. 在 Java 中给定一个数组,将其转换为一个集合。
我们可以使用 Java 中 Arrays 类的 asList() 方法将数组转换为集合。
//including the required header files
import java.util.*;
public class Convert_Array_To_Collection {
public static void main(String args[])
{
//creating a sample array
String sample_array[]
= { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
int length_array = sample_array.length;
System.out.println("The input elements are as follows : ");
for(int i = 0; i < length_array; i ++)
{
System.out.print(sample_array[i] + " ");
}
System.out.println();// setting the print cursor to the next line
List converted_list = Arrays.asList(sample_array);// converting the array to a list
// print converted elements
System.out.println("The converted list is as follows : "
+ converted_list);
}
}
输出:
The input elements are as follows :
Monday Tuesday Wednesday Thursday Friday Saturday Sunday
The converted list is as follows : [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
32. 用 Java 编写一个程序,使用枚举显示 HashTable 的内容。
我们使用 Enumeration 类的 hasMoreElements 和 nextElement 方法来遍历 HashMap。
//including the necessary header files
import java.util.Enumeration;
import java.util.Hashtable;
public class Iterate_HashTable {
public static void main(String[] args) {
Hashtable hash_table = new Hashtable();//creating a hash table
hash_table.put("1", "Monday");
hash_table.put("2", "Tuesday");
hash_table.put("3", "Wednesday");
hash_table.put("4", "Thursday");
hash_table.put("5", "Friday");
hash_table.put("6", "Saturday");
hash_table.put("7", "Sunday");
Enumeration enumeration_hash_table = hash_table.elements();//creating an enumeration object
//while loop runs until the hashtable has more entries in it
while(enumeration_hash_table.hasMoreElements()) {
System.out.println(enumeration_hash_table.nextElement());
}
}
}
输出:
Saturday
Friday
Thursday
Wednesday
Tuesday
Monday
Sunday
我们注意到值的顺序与我们在哈希表中插入键值对的顺序不同。这是因为 Hashtable 的元素不能保证在任何特定的序列中。哈希表的实现根据它们的 Hashcode 和内部实现将值分成多个桶,这意味着相同的值可能在不同的机器、运行或框架的版本上以不同的顺序出现。这是因为 Hashtables 旨在通过键而不是按顺序检索数据。
33. 编写一个程序,用 Java 打乱集合的所有元素。
我们使用 Collections 类的 shuffle() 方法。
//importing the required header files
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Shuffle_collection {
public static void main(String[] argv) throws Exception {
ArrayList array_list = new ArrayList();//creating an arraylist of strings
array_list.add("Monday");
array_list.add("Tuesday");
array_list.add("Wednesday");
array_list.add("Thursday");
array_list.add("Friday");
array_list.add("Saturday");
array_list.add("Sunday");
Collections.shuffle(array_list);//shuffling the arraylist
System.out.println("The shuffled array list is as follows : " + array_list);//printing the shuffled array list
}
}
输出:
The shuffled array list is as follows : [Thursday, Friday, Saturday, Wednesday, Tuesday, Sunday, Monday]
34. 用 Java 编写一个程序,将一个 Treeset 克隆到另一个 Treeset。
我们使用 TreeSet 类的 clone() 方法将一个 TreeSet 克隆到另一个 TreeSet 中。
//importing the required header files
import java.util.TreeSet;
import java.util.Iterator;
public class Clone_Tree_Set {
public static void main(String[] args) {
TreeSet tree_set = new TreeSet();//creating an empty tree set
//adding values in the tree set
tree_set.add("Monday");
tree_set.add("Tuesday");
tree_set.add("Wednesday");
tree_set.add("Thursday");
tree_set.add("Friday");
tree_set.add("Saturday");
tree_set.add("Sunday");
//printing the original tree set
System.out.println("The original tree set is as follows : " + tree_set);
//cloning the tree set
TreeSet cloned_tree_set = (TreeSet)tree_set.clone();
//printing the cloned tree set
System.out.println("The cloned tree set is as follows : " + cloned_tree_set);
}
}
输出:
The original tree set is as follows : [Friday, Monday, Saturday, Sunday, Thursday, Tuesday, Wednesday]
The cloned tree set is as follows : [Friday, Monday, Saturday, Sunday, Thursday, Tuesday, Wednesday]
35. 用 java 编写一个程序来获取 HashMap 中存在的值的集合视图。
我们使用 HashMap 的 values() 函数来获取集合视图。
//importing the required header files
import java.util.*;
public class Collection_View {
public static void main(String args[]){
HashMap hash_map = new HashMap();//creating an empty hash map
//adding key values to the hash map
hash_map.put("1","Monday");
hash_map.put("2","Tuesday");
hash_map.put("3","Wednesday");
hash_map.put("4","Thursday");
hash_map.put("5","Friday");
hash_map.put("6","Saturday");
hash_map.put("7","Sunday");
//printing the original hash map
System.out.println("The original hash map is as follows : " + hash_map);
//printing the collection view of the hash map
System.out.println("The collection view is as follows : " + hash_map.values());
}
}
输出:
The original hash map is as follows: {1=Monday, 2=Tuesday, 3=Wednesday, 4=Thursday, 5=Friday, 6=Saturday, 7=Sunday}
The collection view is as follows : [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
36.用java编写程序,将两个arraylist连接成一个arraylist。
我们使用 ArrayList 类的 addAll() 方法将两个给定数组列表的内容添加到一个新的数组列表中。
//importing the required header files
import java.util.ArrayList;
import java.util.Collections;
public class Join_Lists {
public static void main(String[] args) {
//creating the first array list
ArrayList list_1 = new ArrayList();
list_1.add("Monday");
list_1.add("Tuesday");
list_1.add("Wednesday");
list_1.add("Thursday");
//printing the first array list
System.out.println("The elements of the first array list is as follows : " + list_1);
//creating the second array list
ArrayList list_2 = new ArrayList();
list_2.add("Friday");
list_2.add("Saturday");
list_2.add("Sunday");
//printing the second array list
System.out.println("The elements of the second array list is as follows : " + list_2);
//creating the third array list
ArrayList joined_list = new ArrayList();
joined_list.addAll(list_1);//adding the elements of the first array list
joined_list.addAll(list_2);//adding the elements of the second array list
System.out.println("The elements of the joined array list is as follows : " + joined_list);
}
}
输出:
The elements of the first array list is as follows : [Monday, Tuesday, Wednesday, Thursday]
The elements of the second array list is as follows : [Friday, Saturday, Sunday]
The elements of the joined array list is as follows : [Monday, Tuesday, Wednesday, Thursday, Fri