Java容器

容器

1.Iterable 接口和 Iterator 接口

Iterable 接口从 JDK 1.5 开始出现,是 Java 容器的最顶级的接口之一,该接口的作用是使容器具备迭代元素的功能。

Iterator 接口从 JDK 1.2 开始出现,其含义是迭代器,可以用于迭代容器中的元素。

Iterable 接口的方法

iterator

方法 iteratorIterable 接口的核心方法,返回 Iterator 类的迭代器实例。

forEach

方法 forEach 从 JDK 1.8 开始出现。该方法有默认实现,其作用是对容器中的每个元素进行处理。

spliterator

方法 spliterator 从 JDK 1.8 开始出现。该方法有默认实现,其作用是并行遍历元素。

Iterator 接口的方法

hasNext

方法 hasNext 的作用是检测容器中是否还有需要迭代的元素。

next

方法 next 的作用是返回迭代器指向的元素,并且更新迭代器的状态,将迭代器指向的元素后移一位。

remove

方法 remove 的作用是将迭代器指向的元素删除。

该方法有默认实现,默认实现为抛出 UnsupportedOperationException 异常,如果迭代器迭代的容器不支持 remove 操作,则对迭代器调用方法 remove 时会抛出 UnsupportedOperationException 异常。

forEachRemaining

方法 forEachRemaining 从 JDK 1.8 开始出现。

该方法有默认实现,其作用是对容器中的剩余元素进行处理,直到剩余元素处理完毕或者抛出异常。


2.Collection 接口

Collection 接口统一定义了单列容器,该接口继承了 Iterable 接口。

Collection 接口的常用方法

添加元素

添加元素的方法有 add addAll,其中 add 一次添加一个元素,addAll 一次将另一个容器中的元素全部添加到当前容器中。

方法 addAll 和集合的并集运算相似。

删除元素

删除元素的方法有 removeremoveAll clear

  • remove 一次删除一个元素
  • removeAll 一次将另一个容器中的元素全部从当前容器中删除
  • clear 删除当前容器中的全部元素

方法 removeAll 和集合的差集运算相似。

保留元素

保留元素的方法有 retainAll

该方法保留既在当前容器中又在另一个容器中的元素。

和集合的交集运算相似。

判断包含元素

判断包含元素的方法有 contains containsAll

  • contains 判断当前容器是否包含一个指定元素
  • containsAll 判断当前容器是否包含另一个容器中的全部元素

其他方法

  • 方法 isEmpty 判断当前容器是否为空(即不包含元素)

  • 方法 size 返回容器中的元素数目

  • 方法 toArray 将容器转化成 Object 数组并返回

Collection 接口和其他容器类的关系

ListSetCollection 接口的子接口。

  • List 是线性表,存储一组顺序排列的元素。
  • Set 是集合,存储一组互不相同的元素。

另一个描述容器的接口是 Map,该接口与 Collection 并列存在。

不同于*** Collection 接口存放单值元素,Map 接口存放的是键值对。***


3.线性表

List 接口定义线性表,该接口继承了 Collection 接口。

List 接口的实现类有 ArrayListLinkedListVector

List 接口的常用方法

由于 List 接口继承了 Collection 接口,因此 List 接口支持 Collection 接口的一切方法。

List 接口还支持通过下标访问元素,根据下标进行添加和删除元素的操作,以及可以生成双向遍历线性表的新迭代器。

以下列举的方法是 List 接口中新定义的方法(和 Collection 相比新定义的方法)。

添加元素

添加元素的方法有 add addAll

  • add一次添加一个元素
  • addAll 一次将另一个容器中的元素全部添加到当前线性表中。

这两个方法都可以指定下标,在指定下标处添加元素。

删除元素

删除元素的方法有 remove

可以指定下标,删除指定下标处的元素。

修改元素

修改元素的方法有 set,将指定下标处的元素修改成新的元素。

获得元素以及获得元素下标

获得元素的方法有 get,返回指定下标处的元素。

获得元素下标的方法有 indexOf lastIndexOf,分别返回第一个匹配元素的下标和最后一个匹配元素的下标。

获得子线性表

获得子线性表的方法有 subList,返回指定下标范围的子线性表。

生成线性表迭代器

生成线性表迭代器的方法有 listIterator

  • 该方法如果没有参数则返回线性表中元素的迭代器

  • 如果指定下标则返回从指定下标开始的元素的迭代器

线性表迭代器的接口是 ListIterator,该接口继承了 Iterator 接口,支持双向遍历。

向量类 Vector

Vector 类和 ArrayList 类的方法基本是相同的,主要区别是 Vector 类的所有方法都是同步的,因此可以保证线程安全。

虽然 Vector 是线程安全的,但是同步操作会花费更多的时间。

在不需要保证线程安全的情况下,使用 ArrayList 比使用 Vector 效率更高。

思考

ArrayList LinkedList 的主要区别是什么?从底层实现、随机访问元素、插入和删除元素方面回答。

  • ArrayList 的底层实现是数组,LinkedList 的底层实现是双向链表。
  • ArrayList 可以快速访问指定下标处的元素,LinkedList 需要遍历元素才能得到指定下标处的元素。
  • ArrayList 插入和删除元素时需要移动其他元素(除了在尾部插入和删除元素的情况),LinkedList 可以快速插入和删除元素,但是在指定位置(除了头部和尾部)插入和删除元素时则需要首先遍历元素到指定位置。

ArrayList Vector 的主要区别是什么?什么情况下使用 ArrayList 比使用 Vector 更好?

ArrayListVector 的主要区别是:

  • Vector 的所有方法都是同步的,因此可以保证线程安全,

  • ArrayList 不能保证线程安全。

在不需要保证线程安全的情况下,使用 ArrayList 比使用 Vector 效率更高,因此使用 ArrayList 更好。


4.映射和集合

Map 接口定义映射,存储一组键值对的映射关系。

Set 接口定义集合,存储一组互不相同的元素,该接口继承了 Collection 接口。

Map 接口的概念和常用方法

Map 接口存储一组键值对的映射关系,映射中的每个键对应一个值。映射中不能有重复的键,否则会出现一个键对应多个值的情况,这违背了映射的定义。

放置键值对

放置键值对的方法有 put putAll

  • put 一次放置一个键值对,
  • putAll 一次将另一个映射中的键值对全部添加道当前映射中。

在映射中放置键值对时,如果映射中没有对应的键,则在映射中新建一个键值对,否则用新的键值对覆盖原来的相同键的键值对。

删除键值对

删除键值对的方法有 removeclear

  • remove 删除指定键的键值对
  • clear 删除当前映射中的全部键值对

判断包含键或值

判断包含键或值的方法有 containsKey containsValue

  • containsKey 判断映射中是否包含指定的键
  • containsValue 判断映射中是否包含指定的值

根据键获得值

根据键获得值得方法有 get,该方法返回映射中指定键的值。

获得键或键值对的集合

获得键或键值对的集合的方法有 entrySetkeySet

  • entrySet 返回映射的所有键值对的集合
  • keySet 返回映射的所有键的集合

获得值的容器

获得值的容器的方法有 values,该方法返回映射的所有值的容器。

其他方法

  • 方法 isEmpty 判断当前映射是否为空(即不包含键值对)

  • 方法 size 返回映射中的键值对数目。

Map 接口的实现类 HashMapHashtable TreeMap

HashMap Hashtable

HashMap 类是散列映射,通过散列函数计算键对应的存储位置。

因此可以快速地完成放置键值对、删除键值对、根据键获得值的操作。

JDK 1.8 之前的 HashMap 的底层通过数组和链表实现,如果出现冲突则通过拉链法解决冲突。

JDK 1.8 在解决冲突时的实现有较大变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树,以减少搜索时间。

Hashtable 类是散列表,其功能和 HashMap 相似。

以下是 HashMapHashtable 的部分区别。

  • HashMap 不是线程安全的,Hashtable 的大多数方法用关键字 synchronized 修饰,因此 Hashtable 是线程安全的。
  • 在不需要保证线程安全的情况下,HashMap 的效率高于 Hashtable
  • HashMap 允许键或值为 null,只能有一个键为 null,可以有一个或多个键对应的值为 nullHashtable 不允许键或值为 null
  • 从 JDK 1.8 开始,HashMap 在链表长度大于阈值(默认为 8)时,将链表转化为红黑树以减少搜索时间,Hashtable 没有这样的机制。

TreeMap

TreeMap 是有序映射,键可以使用 Comparable 接口或 Comparator 接口排序。

TreeMap 的底层实现是红黑树,通过红黑树维护映射的有序性。由于要维护映射的有序性,因此 TreeMap 的各项操作的平均效率低于 HashMap,但是 TreeMap 可以按照顺序获得键值对。

Set 接口的定义和常用方法

Set 接口存储一组互不相同的元素,一个集合中不存在两个相等的元素。

Set 接口继承了 Collection 接口,没有引入新的方法或常量,只是规定其实例不能包含相等的元素。

Set 接口的实现类 HashSet 和 TreeSet

HashSet

HashSet 类是散列集合,其底层实现基于 HashMap

  • 当对象加入散列集合时,需要判断元素是否重复,
    • 首先通过方法 hashCode 计算对象的散列码检查是否有对象具有相同的散列码,
    • 如果没有相同的散列码则没有重复元素,否则再通过方法 equals 检查是否有相等的对象。

根据散列约定,如果两个对象相同,它们的散列码一定相同。

因此如果在子类中重写了 equals 方法,必须在该子类中重写 hashCode 方法,以保证两个相等的对象对应的散列码是相同的。

TreeSet

TreeSet 类是有序集合,其底层实现基于 TreeMap

TreeMap 相似,TreeSet 可以使用 Comparable 接口或 Comparator 接口对元素排序。

HashSet 的底层实现基于 HashMap,元素是无序的,通过方法 hashCode equals 保证元素没有重复;TreeSet 的底层实现基于 TreeMap,元素是有序的,通过 Comparable 接口或 Comparator 接口保证元素没有重复。

posted @ 2022-05-27 09:31  萝卜不会抛异常  阅读(57)  评论(0编辑  收藏  举报