diff --git a/docs/java/collection/Java集合框架常见面试题.md b/docs/java/collection/Java集合框架常见面试题.md index 973d3d95..734e3aa0 100644 --- a/docs/java/collection/Java集合框架常见面试题.md +++ b/docs/java/collection/Java集合框架常见面试题.md @@ -9,16 +9,16 @@ * [1.1.3 如何选用集合?](#-1) * [1.1.4 为什么要使用集合?](#-1) * [1.2 Iterator迭代器接口](#Iterator) + * [1.2.1 为什么要使用迭代器](#1.2.1为什么要使用迭代器) * [1.3 Collection子接口之List](#CollectionList) * [ 1.3.1 Arraylist 与 LinkedList 区别?](#ArraylistLinkedList) - * [**补充内容:RandomAccess接口**](#:RandomAccess) - * [补充内容:双向链表和双向循环链表](#:) - * [1.3.2 ArrayList 与 Vector 区别呢?为什么要用Arraylist取代Vector呢?](#ArrayListVectorArraylistVector) - * [1.3.3 说一说 ArrayList 的扩容机制吧](#ArrayList) + * [1.3.2 说一说 ArrayList 的扩容机制吧](#ArrayList) * [1.4 Collection子接口之Set](#CollectionSet) * [1.4.1 comparable 和 Comparator的区别](#comparableComparator) * [Comparator定制排序](#Comparator) * [重写compareTo方法实现按年龄来排序](#compareTo) + * [1.4.2 无序性和不可重复性的含义是什么](#1.4.2无序性和不可重复性的含义是什么) + * [1.4.3 比较HashSet 、LinkedHashSet和TreeSet三者的异同 ](#1.4.3比较HashSet、LinkedHashSet和TreeSet三者的异同 ) * [1.5 Map接口](#Map-1) * [1.5.1 HashMap 和 Hashtable 的区别](#HashMapHashtable) * [1.5.2 HashMap 和 HashSet区别](#HashMapHashSet) @@ -52,14 +52,14 @@ ##### List -- **Arraylist:** Object数组 -- **Vector:** Object数组 +- **Arraylist:** Object[]数组 +- **Vector:** Object[]数组 - **LinkedList:** 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环) ##### Set - **HashSet(无序,唯一):** 基于 HashMap 实现的,底层采用 HashMap 来保存元素 -- **LinkedHashSet:** LinkedHashSet 继承于 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的 +- **LinkedHashSet:** LinkedHashSet 是 HashSet的子类,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的 - **TreeSet(有序,唯一):** 红黑树(自平衡的排序二叉树) #### Map @@ -81,47 +81,17 @@ 但是集合提高了数据存储的灵活性,Java集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据 ## 1.2 Iterator迭代器接口 +### 1.2.1 为什么要使用迭代器 +Iterator对象称为迭代器(设计模式的一种),迭代器可以对集合进行遍历,但每一个集合内部的数据结构可能是不尽相同的,所以每一个集合存和取都很可能是不一样的,虽然我们可以人为地在每一个类中定义 hasNext() 和 next() 方法,但这样做会让整个集合体系过于臃肿。于是就有了迭代器。 + +迭代器是将这样的方法抽取出接口,然后在每个类的内部,定义自己迭代方式,这样做就规定了整个集合体系的遍历方式都是hasNext()和next()方法,使用者不用管怎么实现的,会用即可。迭代器的定义为:提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。 ## 1.3 Collection子接口之List -### 1.3.1 Arraylist 与 LinkedList 区别? +### 1.3.1 Arraylist、LinkedList与Vector的区别? -- **1. 是否保证线程安全:** `ArrayList` 和 `LinkedList` 都是不同步的,也就是不保证线程安全; - -- **2. 底层数据结构:** `Arraylist` 底层使用的是 **`Object` 数组**;`LinkedList` 底层使用的是 **双向链表** 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!) - -- **3. 插入和删除是否受元素位置的影响:** ① **`ArrayList` 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。** 比如:执行`add(E e) `方法的时候, `ArrayList` 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(`add(int index, E element) `)时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② **`LinkedList` 采用链表存储,所以对于`add(E e)`方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置`i`插入和删除元素的话(`(add(int index, E element)`) 时间复杂度近似为`o(n))`因为需要先移动到指定位置再插入。** - -- **4. 是否支持快速随机访问:** `LinkedList` 不支持高效的随机元素访问,而 `ArrayList` 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于`get(int index) `方法)。 - -- **5. 内存空间占用:** ArrayList的空间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。 - -#### **补充内容:RandomAccess接口** - -```java -public interface RandomAccess { -} -``` - -查看源码我们发现实际上 `RandomAccess` 接口中什么都没有定义。所以,在我看来 `RandomAccess` 接口不过是一个标识罢了。标识什么? 标识实现这个接口的类具有随机访问功能。 - -在 `binarySearch()` 方法中,它要判断传入的list 是否 `RamdomAccess` 的实例,如果是,调用`indexedBinarySearch()`方法,如果不是,那么调用`iteratorBinarySearch()`方法 - -```java - public static - int binarySearch(List> list, T key) { - if (list instanceof RandomAccess || list.size()