Java集合类中的List、Set和Map及其实现类的详细介绍

集合类放在java的util包下面,集合类存放的都是对象的引用,而非对象本身,

常见的集合有三种:Set、List、Map

  • List和Set实现了Collection接口,List和Set本身也是接口,Map为独立接口。
  • List实现的类:ArrayList、Vector、LinkedList
  • Set实现的类:HashSet、LinkedHashSet、TreeSet、ArraySet
  • Map实现的类:HashMap、TreeMap、Hashtable

一、Collection接口

Collection接口是Java集合框架中的一个根接口,它代表了一组对象,称为元素。这个接口本身并不直接实现任何数据结构,而是定义了一些基本的操作方法,这些方法可以被所有实现了Collection接口的集合类所共享。

添加元素

  • boolean add(E e) :将指定的元素添加到此集合中(可选操作)。
  • boolean addAll(Collection<? extends E> c) :将指定集合中的所有元素添加到此集合中(可选操作)。

移除元素

  • boolean remove(Object o) :从此集合中移除指定元素的单个实例,如果存在的话(可选操作)。
  • boolean removeAll(Collection<?> c) :移除此集合中那些也包含在指定集合中的所有元素(可选操作)。
  • void clear() :移除此集合中的所有元素(可选操作)。

检查元素

  • boolean contains(Object o) :如果此集合包含指定的元素,则返回true。
  • boolean containsAll(Collection<?> c) :如果此集合包含指定集合中的所有元素,则返回true。
  • boolean isEmpty() :如果此集合不包含元素,则返回true。

获取集合大小

  • int size() :返回此集合中的元素数(其容量)。

遍历集合

  • Iterator<E> iterator() :返回在此集合元素上进行迭代的迭代器。

除了上述基本方法外,Collection接口还定义了其他一些可选操作,如转换为数组的方法 Object[] toArray()<T> T[] toArray(T[] a) ,以及确保此集合的可修改性的方法 boolean retainAll(Collection<?> c)(仅保留此集合中也包含在指定集合中的元素)。

Java集合框架中提供了多种实现了Collection接口的类,如List、Set和Queue等。这些类各自具有不同的特性,如List是有序的,允许重复元素;Set是无序的,不允许重复元素;Queue则遵循FIFO原则。

1、List:ArrayList

ArrayList 是 Java 编程语言中的一个类,它实现了 List 接口,主要用于在内存中存储对象的动态数组。ArrayList 提供了一种灵活的方式来存储和操作对象列表,可以 动态地调整其大小

  • 动态数组: ArrayList 在内部使用数组来存储元素,但它能够动态地增长和缩小以适应元素数量的变化。当向 ArrayList 添加元素时,如果当前数组的大小不足以容纳新元素,ArrayList 会 自动创建一个更大的数组 ,并将现有元素复制到新数组中。同样,当从 ArrayList 中删除元素时,如果数组的大小过大,它可能会缩小其大小以节省内存。
  • 随机访问: 由于 ArrayList 在内部使用数组,因此可以通过索引快速访问任意位置的元素。这使得 ArrayList 在需要频繁访问列表中元素的情况下非常高效。
  • 顺序存储: ArrayList 中的元素按照它们被 添加到列表中的顺序存储 。这意味着可以通过迭代列表来按顺序访问元素。
  • 失败快速: ArrayList 在大多数情况下的性能都非常好,尤其是在随机访问和尾部插入或删除操作方面。然而,在列表的开头插入或删除元素时,由于需要将所有后续元素向前或向后移动一位,因此性能可能较差
  • 线程不安全: ArrayList 不是线程安全的 。如果多个线程同时修改 ArrayList,可能会导致数据不一致或其他并发问题。在多线程环境中使用 ArrayList 时,需要额外的同步措施来确保线程安全。
  • 容量和大小: ArrayList 有两个重要的属性:容量(capacity)大小(size) 。容量是 ArrayList 当前分配的存储空间大小,而大小是实际存储在 ArrayList 中的元素数量。可以通过调用 ensureCapacity() 方法来增加容量,但请注意,这并不会改变 ArrayList 的大小。同样,可以通过调用 add() 方法来增加大小,如果这导致容量不足,ArrayList 会自动增加其容量。

ArrayList 是一个功能强大且灵活的集合类,适用于需要在内存中存储和操作对象列表的场景。

在选择使用 ArrayList 时,需要考虑到其线程不安全性和在列表开头进行插入/删除操作时的性能问题。

2、List:Vector

Vector是一个表示可以改变大小的数组的序列容器,类似于数组,但具有 动态调整大小 的能力。

  • 动态数组: Vector可以 动态地增长和缩小 以适应元素的添加和删除。当需要添加新元素而当前空间不足时,Vector会自动重新分配更大的存储空间,并将现有元素移至新的存储空间。
  • 顺序序列: Vector中的元素按照 严格的线性顺序排列 ,可以通过元素在序列中的位置(即下标)来访问对应的元素。
  • 高效随机访问: Vector提供了常数时间复杂度 O(1) 的随机访问能力,可以快速访问任意位置的元素。
  • 自动内存管理: Vector自动处理其存储空间的分配和释放,无需手动管理内存。

Vector在多个领域都有广泛的应用:

  • 动态数据集合: 当数据集的大小不确定或会随时间变化时,Vector是理想的选择。例如,处理用户输入或读取文件数据时,Vector可以根据需要动态地增长。
  • 替代数组: 在编程中,Vector通常被用来替代传统的固定大小数组,因为它更加灵活且自动管理内存。
  • 数学和科学计算: 在科学计算、物理模拟、数学建模等领域中,Vector用于存储和操作大量数值数据,如矩阵的行或列。
  • 游戏开发和图形处理: Vector可用于存储游戏对象、粒子、坐标点等动态集合,以及图形处理程序中的像素数据、顶点信息、纹理坐标等。

Vector是一个功能强大且灵活的容器类,适用于需要动态存储和访问元素序列的场景。

由于Vector在添加或删除元素时可能需要重新分配存储空间,因此在某些情况下可能会带来一定的性能开销。因此,在选择使用Vector时,需要根据具体的应用场景和需求进行权衡。

3、List:LinkedList

LinkedList是一个基于链表实现的 动态数据结构 ,它的大小可以在运行时根据需要进行调整。LinkedList通过节点来存储数据,每个节点不仅包含数据元素,还包含 指向前后节点的指针 ,这种结构使得LinkedList在插入和删除元素时具有非常高的性能。

  • 动态大小: 当元素数量超过当前容量时,LinkedList会 自动扩展 其大小,无需预先分配固定大小的空间。
  • 高效的插入和删除: 由于LinkedList中的元素是通过 指针相互连接 的,因此在插入或删除元素时,只需要修改相关节点的指针,而不需要动大量元素。这使得LinkedList在插入和删除操作上的性能优于某些其他数据结构,如ArrayList。
  • 较低的随机访问性能: LinkedList不支持像数组那样的直接索引访问,而是需要从链表头部或尾部遍历到指定的位置。因此,当需要频繁访问链表中间的元素时,LinkedList的性能可能不如ArrayList。
  • 灵活的使用方式: LinkedList可以作为栈、队列或双端队列来使用 ,这使得它在处理各种数据结构问题时具有很高的灵活性。
  • 非线程安全: 与ArrayList类似,LinkedList也是 非线程安全 的。如果需要在多线程环境中使用LinkedList,需要额外的同步措施来确保线程安全。

LinkedList是一个功能强大且灵活的数据结构,适用于需要频繁进行插入和删除操作,但对随机访问性能要求不高的场景。

在选择使用LinkedList时,需要考虑到其 随机访问性能较低 的特点,并结合具体的应用需求进行权衡。

4、Set:HashSet

HashSet是Java中的一个重要集合类,它实现了Set接口,主要用于 存储不重复 的元素。HashSet内部使用HashMap来实现,因此它同样具有高效的性能表现。

  • 不重复元素: HashSet不允许存储重复的元素 。当你试图将一个已经存在于集合中的元素添加到HashSet时,添加操作将不会有任何效果,即该元素不会被重复添加。
  • 无序性: HashSet不保证元素的迭代顺序与它们的插入顺序一致。也就是说,每次遍历HashSet时,元素的顺序可能会有所不同。
  • 基于HashMap实现: HashSet内部实际上是通过HashMap来实现的 。每个元素都作为HashMap的一个键(key),而值(value)则是一个固定的对象。这种实现方式使得HashSet在添加、删除和查找元素时都能保持较高的性能。
  • 快速查找: 由于HashSet基于HashMap实现,因此它具有常数时间复杂度 O(1) 的查找性能。这意味着无论集合中包含多少元素,查找一个特定元素所需的时间都是固定的。
  • 自动扩容: 当HashSet中的元素数量超过当前容量时,它会 自动进行扩容 ,以确保能够容纳更多的元素。这种动态扩容的特性使得HashSet在处理大量数据时非常灵活和高效。
  • 非线程安全: 与ArrayList和LinkedList一样,HashSet也是 非线程安全 的。如果需要在多线程环境中使用HashSet,需要额外的同步措施来确保线程安全。

HashSet是一个用于 存储不重复元素高效集合类 ,适用于需要快速查找和添加元素,且不关心元素顺序的场景。

在使用HashSet时,需要注意其非线程安全性的特性,并在必要时采取适当的同步措施。

5、Set:LinkedHashSet

LinkedHashSet是Java中的一个集合类,它是HashSet的子类,并基于LinkedHashMap实现。LinkedHashSet的主要特点是既保持了元素的插入顺序,又保证了元素的唯一性。

  • 有序性: LinkedHashSet继承了HashSet的唯一性特性 ,同时 增加了有序性 。它使用双向链表来维护元素的插入顺序,确保在迭代时元素会按照它们被添加到集合中的顺序返回。这种有序性使得LinkedHashSet在需要按照特定顺序处理元素时非常有用。
  • 唯一性: 与HashSet一样,LinkedHashSet也保证集合中元素的唯一性 。它使用元素的hashCode()方法和equals()方法来检查是否存在重复元素,并在添加时自动排除重复项。
  • 基于LinkedHashMap实现: LinkedHashSet内部实际上是通过LinkedHashMap来实现的。每个元素都作为LinkedHashMap的一个键(key),而值(value)则是一个固定的对象。这种实现方式不仅保留了元素的插入顺序,还继承了HashMap的高效性能。
  • 高效性能: 由于LinkedHashSet基于LinkedHashMap实现,它继承了HashMap的高性能特点。在添加、删除和查找元素时,LinkedHashSet都能保持较高的性能,特别是在处理大量数据时表现尤为出色。
  • 动态扩容: 当LinkedHashSet中的元素数量超过当前容量时,它会 自动进行扩容 ,以确保能够容纳更多的元素。这种动态扩容的特性使得LinkedHashSet在处理大量数据时非常灵活和高效。
  • 非线程安全: 与HashSet等其他集合类一样,LinkedHashSet也是 非线程安全的 。如果需要在多线程环境中使用LinkedHashSet,需要额外的同步措施来确保线程安全。

LinkedHashSet的特点主要体现在有序性、唯一性、高效性能和动态扩容等方面。 它适用于需要按照插入顺序存储并处理唯一元素的场景,特别是在对性能要求较高的应用中表现出色。然而,在使用LinkedHashSet时,需要注意其非线程安全性的特性,并在必要时采取适当的同步措施。

LinkedHashSet是一个结合了有序性和唯一性的高效集合类,适用于需要按照插入顺序存储并处理唯一元素的场景。

6、Set:TreeSet

TreeSet是Java集合框架中的一种有序集合,它实现了Set接口,因此具有不允许重复元素的特性。TreeSet通过红黑树数据结构来存储元素,这使得元素在集合中保持有序。

TreeSet中的元素支持两种排序方式 :自然排序和根据创建TreeSet时提供的Comparator进行排序。自然排序是根据元素的自然顺序来排列,而Comparator排序则是根据提供的比较器来定义元素的顺序。

  • 有序性: TreeSet中的元素按照特定的顺序排列,这使得遍历TreeSet得到的元素是按照一定的顺序返回的。这种有序性为应用场景下的迭代和顺序处理提供了便利。
  • 唯一性: 与HashSet一样,TreeSet也 保证元素的唯一性 ,不允许重复元素。
  • 高效的查找、插入、删除操作: 由于TreeSet基于红黑树实现,其查找、插入和删除操作的时间复杂度为 O(log(n)) ,因此适用于大批量数据的操作。
  • 支持范围查找: TreeSet支持返回第一个大于等于或小于等于给定值的元素,这能满足一些特殊业务需求。
  • 线程安全: TreeSet具有底层数据结构红黑树的特性,包括平衡、高效以及线程安全。

TreeSet还继承了AbstractSet抽象类和实现了NavigableSet、Cloneable、java.io.Serializable接口,因此它具有Set的属性和方法,支持一系列的导航方法,能被克隆,并支持序列化。

TreeSet是一个有序的、唯一的元素集合,适用于需要有序存储唯一元素的场景。

在使用TreeSet时,需要注意其元素的排序方式以及线程安全性的考虑。

7、Queue:队列

Queue与List、Set同一级别,都是继承了Collection接口,LinkedList即可以实现Queue接口,也可以实现List接口,若实现Queue接口,会窄化LinkedList的方法的访问权限:即不能直接访问LinkedList的非Queue的方法。

Queue(队列)是一种特殊类型的线性数据结构,它遵循FIFO(First In First Out,先入先出)的原则,即最早加入的元素将是最先被移除的元素。Queue提供了在表的前端进行删除操作,而在表的后端进行插入操作的能力。

  • 入队(Enqueue): 在队列的尾部添加一个元素。
  • 出队(Dequeue): 移除队列的头部元素,并返回该元素。如果队列为空,则无法进行出队操作。
  • 查看队首(Peek): 返回队列头部的元素,但不移除它。如果队列为空,则返回特定值(如null或抛出异常)。
  • 检查队列是否为空(IsEmpty): 检查队列中是否还有元素。
  • 获取队列大小(Size): 返回队列中当前元素的数量。

Queue在实际应用中有许多用途,特别是在需要按照特定顺序处理元素的情况下。

例如,在多线程编程中,Queue经常被用作线程之间的 通信桥梁 ,一个线程可以将任务或数据放入队列,另一个线程可以从队列中取出任务或数据进行处理。此外,在计算机系统的许多其他方面,如网络数据包的处理、任务调度等,Queue都发挥着重要的作用。

Java标准库提供了几种Queue的实现,包括LinkedList、PriorityQueue、ArrayBlockingQueue等,它们各自具有不同的特性和适用场景。

二、Map接口

Map接口是Java编程中非常重要的一个接口,它用于存储键值对(key-value pair)的映射关系。Map接口提供了一种通过键来查找值的方式,其中键和值都可以是任意的Java对象。

Map接口定义了一系列用于 操作映射关系 的方法,例如添加、删除、更新和查询元素等。它允许用户根据键快速查找对应的值。Map中的键必须是唯一的,每个键最多映射到一个值。 此外,Map接口的实现类可以存储任意类型的键值对,这为用户提供了很大的灵活性。

在Java中,Map接口有多个实现类,如HashMap、Hashtable、TreeMap和LinkedHashMap等。

Map接口本身并不直接支持遍历操作 ,但可以通过keySet()或entrySet()方法将其转换为Set,从而进行遍历。此外,Map中的键不允许为null(HashMap和LinkedHashMap允许一个null键),而值可以为null(HashMap和LinkedHashMap允许多个null值,但TreeMap不允许null键或null值)。

Map接口为Java编程提供了强大的键值对存储和查找功能,能够方便地处理各种映射关系。

1、HashMap

HashMap是Java中Map接口的一个常用实现类,它基于哈希表数据结构来实现键值对的存储和查找。

  • 高效性能: HashMap通过 哈希表 来实现元素的存储和查找,因此具有非常高效的性能。在理想情况下,HashMap的查找、插入和删除操作的时间复杂度都是 O(1) ,即常数时间复杂度。这使得HashMap在处理大量数据时能够保持出色的性能。
  • 无序性: HashMap不保证元素的顺序,即遍历HashMap时,元素的顺序可能与插入的顺序不一致。如果需要保持元素的顺序,可以考虑使用LinkedHashMap。
  • 允许null键和null值: HashMap允许键(key)和值(value)为null,但键只能有一个为null,值可以有多个为null。 这一特性使得HashMap在某些场景下非常方便。
  • 动态扩容: 当HashMap中的元素数量超过当前容量的一定阈值时,HashMap会 自动进行扩容 ,以容纳更多的元素。扩容过程中会重新计算哈希值并移动元素,因此扩容操作可能会涉及到较大的性能开销。为了避免频繁扩容,可以在创建HashMap时指定一个合适的初始容量和加载因子。
  • 冲突处理: 由于哈希表的特性,不同的键可能会计算出相同的哈希值,从而导致 冲突 。HashMap通过链表或红黑树来解决冲突。当冲突较少时,HashMap使用链表来存储具有相同哈希值的键值对;当冲突较多时,链表会转换为红黑树以提高查找性能。

在使用HashMap时,需要注意以下几点:

  • 键(key)必须是唯一的,不能重复。 如果插入具有相同键的键值对,后插入的值会覆盖先插入的值
  • 尽量避免使用可变对象作为键。 因为HashMap在存储键值对时会计算键的哈希值,并在后续操作中依赖这个哈希值。如果键对象在HashMap中发生变化,其哈希值也可能发生变化,导致HashMap无法正确查找或删除元素。
  • 当HashMap中的元素数量较多时,扩容操作可能会带来较大的性能开销。 因此,在创建HashMap时,最好根据预期的元素数量来 指定一个合适的初始容量和加载因子,以减少扩容次数

HashMap结构

HashMap是散列表的数据结构,即数组和链表的结合体,底层是一个数组结构,而数组结构中的每一项元素又是一个链表结构,即Entry<k, v>,Entry就是数组中的元素,每个Map.Entry其实就是一个key-value键值对,它持有指向下一个的引用。

  • ① --> Entry<k, v>
  • ② --> Entry<k, v> --> Entry<k, v>
  • ③ --> Entry<k, v>
  • ④ …
  • ⑤ --> Entry<k, v> --> Entry<k, v> --> Entry<k, v>

解释:

  • 数组:HashMap以键值对的方式存储结构,其中key-value都是Map.Entry中的属性。数组的下标对应key值,数组的值对应value
  • 对应的过程:将key值进行Hash后得到Hash值,若Hash值的范围大与数组长度的话,就需要转换,对数组的长度进行取模运算 ,得到的余数即为存放的下标key,HashMap的长度一般是2的幂次方,是为了提高模运算的效率。
  • 链表:经过上述操作,会出现相同的下标key,即产生了 Hash冲突 ,采用链表的方式进行存储,如果key相同,则覆盖原始值。如果key出现冲突,就将当前的key-value值放入链表,进一步对比value值,不同,则放入链表的下一个节点。

Hash取模详细解释:

  • 通过put()方法传递键key和值value时,先对键调用hashCode方法,计算并返回hashCode值用于找到Map数组的位置来存储Entry对象,hashCode方法是根据key的hash值来求对应数组中的位置。使用hashCode对数组的长度进行取模运算,元素尽量分布的均匀一点取模后取得相同的值即为hash冲突 。取模相同的要使用equals方法去判断,相同的话不存储,不相同的话就存储到链表的下一个节点。

2、Hashtable

Hashtable是Java中基于 哈希表 (Hash Table)实现的一种数据结构,用于存储键值对(key-value pair)。Hashtable的主要目的是提供一种快速查找和存储数据的方式。它通过哈希函数将键映射到存储位置,从而实现了高效的插入、删除和查找操作。

  • 唯一键: Hashtable中的键(key)必须是唯一的,每个键最多映射到一个值(value)。这意味着如果你尝试插入具有相同键的新键值对,那么新值会覆盖旧值。
  • 线程安全: Hashtable是 线程安全 的,这意味着在多线程环境中,多个线程可以同时读写Hashtable而不会导致数据不一致。然而,线程安全也带来了一定的性能开销。如果需要更高的性能,并且可以接受一定程度的线程不安全,可以考虑使用HashMap。
  • 性能: 通过哈希函数,Hashtable可以快速定位到存储的数据位置,因此查找速度快。同时,插入和删除操作也相对高效,因为只需要计算一次哈希函数即可。
  • 冲突处理: 哈希函数并不是完美的,有时会出现多个键映射到同一个位置的情况,这种情况称为哈希冲突。为了解决哈希冲突问题,Hashtable通常采用拉链法或开放寻址法

虽然Hashtable提供了线程安全,但在高并发的场景下,其性能可能不如其他非线程安全的哈希表实现(如HashMap)。此外,由于Hashtable是较老的Java集合类,一些新的Java特性(如泛型)在Hashtable中并未得到很好的支持。

3、TreeMap

TreeMap是Java中的一种集合类,它实现了SortedMap接口,这意味着TreeMap中的元素可以按照键的自然顺序或者自定义顺序进行排序。TreeMap的底层实现采用了红黑树(Red-Black Tree)的数据结构,这种数据结构能够确保TreeMap在动态插入、删除和修改键值对时,仍然能够保持元素的有序性。

  • 排序: TreeMap中的键值对按照键的顺序进行排序。默认情况下,它按照键的自然顺序进行排序,但也可以通过构造函数传入自定义的Comparator来实现特定的排序规则。
  • 有序性: 由于TreeMap是 按照键的顺序存储元素的 ,因此在遍历时可以按照排序顺序获取或操作元素。这种有序性使得TreeMap在处理需要排序的场景时非常有用。
  • 动态更新: TreeMap支持 动态 插入、删除和修改键值对操作,这些操作会保持元素的有序性。也就是说,无论何时进行更新操作,TreeMap都能够保持其内部元素的排序状态。
  • 范围查询: TreeMap提供了一系列的方法来支持范围查询,例如headMap、tailMap和subMap等。这些方法可以根据指定的范围获取子映射,使得在处理需要按照键的范围来查询和操作数据的场景时非常高效。

TreeMap主要适用于需要排序和范围查询的场景。

例如,当需要按照键的顺序访问和处理数据时,可以使用TreeMap来存储键值对,并利用其排序特性方便地进行相关操作。此外,当需要根据键的范围来查询和操作数据时,TreeMap提供的范围查询方法能够快速地定位所需的子映射。

在使用TreeMap时,需要注意 自定义比较器 的情况。如果元素不实现Comparable接口,或者需要按照不同的方式进行排序,可以通过构造函数传入自定义的Comparator来实现特定的排序规则。同时,为了保证线程安全,可以使用Collections.synchronizedSortedMap进行包装,或者使用ConcurrentSkipListMap作为线程安全的替代。

4、LinkedHashMap

LinkedHashMap是Java中的一种特殊类型的HashMap,它继承自HashMap并实现了Map接口。与普通的HashMap不同,LinkedHashMap在内部使用双向链表维护了插入顺序或者访问顺序,从而保证了元素的顺序。

  • 有序性: LinkedHashMap按照 元素的插入顺序或访问顺序进行排序和存储 ,因此,在迭代LinkedHashMap时,元素会按照它们被插入或访问的顺序返回。这种有序性使得LinkedHashMap非常适合于需要保持元素顺序的场景。
  • 高效性: 由于LinkedHashMap底层使用哈希表实现,因此它具有HashMap的高效查找和访问特性。可以快速进行元素的查找、插入和删除操作。
  • 可预测性: 由于LinkedHashMap维护了元素的顺序,因此它提供了可预测的遍历顺序。这在某些需要按照特定顺序处理元素的场景中非常有用。

LinkedHashMap的用途广泛,例如在需要实现LRU(Least Recently Used,最近最少使用)缓存的场景中,LinkedHashMap可以根据元素的访问顺序进行缓存淘汰。此外,它还可以用于实现有序的映射表,保持元素按照插入顺序或访问顺序排列。

需要注意的是,虽然LinkedHashMap保持了元素的顺序,但在多线程环境下使用时,仍然需要注意线程安全问题。如果需要在多线程环境中使用LinkedHashMap,可以考虑使用其线程安全的版本,或者使用其他线程安全的集合类。

三、List、Set、Map是否可以为null值

1、List的实现类

  • 大部分List的实现类(如ArrayList, LinkedList等)都允许存储null值作为列表的元素。例如,你可以向ArrayList中添加一个null元素。
  • List本身(即List类型的引用)也可以被设置为null。这取决于你如何初始化或赋值给这个引用。

2、Set的实现类

  • Set的实现类(如HashSet, TreeSet等)一般不允许存储重复的元素。但是,它们是否可以存储null值取决于具体的实现。例如,HashSet允许存储一个null元素但TreeSet不允许(因为TreeSet需要元素之间可比较,而null不能参与比较)。
  • Set本身(即Set类型的引用)也可以被设置为null。

3、Map的实现类

  • Map的实现类(如HashMap, TreeMap, Hashtable等)对于键和值的处理各不相同。例如,HashMap允许键和值都可以是null。TreeMap不允许null键,但值可以是null。Hashtable则不允许键或值为null。
  • Map本身(即Map类型的引用)同样可以被设置为null。

4、总结

  • List允许存储的值为null,并且可以存储多个,不会对数据结构造成影响。
  • HashSet、LinkedHashSet底层为HashMap,可以有1个为null的元素。
  • TreeSet不能有key为null的元素,需要进行元素之间的比较,会报空指针错误。
  • HashMap只能有一个key为null的节点,因为Map的key相同时,后面的节点会替换之前的key。
  • TreeMap会调用CompareTo方法,对象为null时会报空指针错误。
  • Hashtable底层为散列表,无论是key为null或者value为null,都会报错。
  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值