Java 4.9 container interview

What is 4.9.1 Java Collections Framework

Java Collections framework includes a collection of a large number of interfaces, and these interfaces and classes implemented algorithm operation thereof (e.g., sort, search, reversed, replaced, repeated, taking the smallest element, taking the maximum elements, etc.), specifically, mainly provided list (list), queue (queue), the set (set), stack (stack) and map (mapping table for storing key-value pairs), and other data structures. Which, List, Queue, Set, Stack are inherited from the Collection interface.

The following describes the Set, List and Map 3 interfaces.

1) Set represents the set of concepts in a mathematical sense. Its main feature is the set of elements can not be repeated, so that each element is stored Set must define equals () method to ensure the uniqueness of the object. The interface has two implementation classes: Hash-Set and TreeSet. Wherein TreeSet SortedSet implements the interface, thus TreeSet container elements are ordered.

2) List, also known as orderly Collection. It is in order to save the object into the object, so that it can be precisely controlled for insertion and deletion position in the list each element. At the same time, it can save duplicate objects. LinkedList, Array-List and Vector have achieved the List interface.

3) Map data structure provides a mapping from keys to values. It is used to store key-value pair, where the values ​​may be repeated, but the key is unique and can not be repeated. Java class library with a plurality of classes that implement the interface: HashMap, TreeMap, Linked-HashMap, WeakHashMap and IdentityHashMap. Although they all implement the same interface, but the efficiency is not exactly the same. Specifically, HashMap is based on the hash table implemented using object HashCode can quickly query. LinkedHashMap using the list to maintain internal order. TreeMap based on the internal structure of the data elements of the red-black tree is needed to achieve the arrangement.

 Map is an interface, can not be directly instantiated Map objects, but can instantiate an object that implements the class Map interface, e.g. Map m = new HashMap ()


4.9.2 What is an iterator

Iterator (the Iterator) is an object, its job is to select an object and traversal sequence, which provides access to a respective element of a container object (Container), the internal details of the method but without having to expose the subject. By iterator, developers do not need to understand the underlying structure of the container, it can be achieved traversal of the container. Due to the small to create the iterator price, therefore iterator is often called lightweight containers.

Iterator's main considerations of the following three areas:

1) use of the container iterator () method returns an Iterator, and () method returns the first element by the next Iterator.

2) Use the Iterator hasNext () method determines whether there are elements in the container, if any, may be used next () method to get the next element.

3) You can delete an element iterator returned by the remove () method.

Brotherhood members support Iterator derived. ListIterator exists only in the List, to add support to the List during iteration or delete elements, and can be bi-directional scrolling in List.

When using iterator () method often encounter ConcurrentModificationException exception, this is usually due to the use Iterator to traverse the container and container do add or delete operation has caused, or due to multithreading lead, when a thread using an iterator while traversing the container, another thread on this vessel add or delete operation.

The following example describes the case of a single-threaded throw ConcurrentModificationException:

Described above single-threaded solution, then the process of multi-threaded access to the container thrown ConcurrentModifi-cationException abnormal how should we solve it?

1)在 JDK 1.5 版本引入了线程安全的容器,比如 ConcurrentHashMap 和 CopyOnWriteArray-List 等。可以使用这些线程安全的容器来代替非线程安全的容器。

2)在使用迭代器遍历容器时对容器的操作放到 synchronized 代码块中,但是当引用程序并发程度比较高时,这会严重影响程序的性能。

引申:Iterator 与 ListIterator 有什么区别?

Iterator 只能正向遍历集合,适用于获取移除元素。ListIerator 继承自 Iterator,专门针对 List,可以从两个方向来遍历 List,同时支持元素的修改。


4.9.3 ArrayList、Vector 和 LinkedList 有什么区别

ArrayList、Vector、LinkedList 类均在 java.util 包中,均为可伸缩数组,即可以动态改变长

ArrayList 和 Vector 都是基于存储元素的 Object[]array 来实现的,它们会在内存中开辟一块连续的空间来存储,由于数据存储是连续的,因此,它们支持用序号(下标)来访问元素,同时索引数据的速度比较快。但是在插入元素时需要移动容器中的元素,所以对数据的插入操作执行得比较慢。ArrayList 和 Vector 都有一个初始化的容量的大小,当里面存储的元素超过这个大小时就需要动态地扩充它们的存储空间。为了提高程序的效率,每次扩充容量,不是简单地扩充一个存储单元,而是一次增加多个存储单元。Vector 默认扩充为原来的 2 倍(每次扩充空间的大小是可以设置的),而 ArrayList 默认扩充为原来的 1.5 倍(没有提供方法来设置空间扩充的方法)。

ArrayList 与 Vector 最大的区别就是 synchronization(同步)的使用,没有一个 ArrayList 的方法是同步的,而 Vector 的绝大多数方法(例如 add、insert、remove、set、equals、hashcode 等)都是直接或者间接同步的,所以 Vector 是线程安全的,ArrayList 不是线程安全的。正是由于 Vector 提供了线程安全的机制,其性能上也要略逊于 ArrayList。

LinkedList 是采用双向列表来实现的,对数据的索引需要从列表头开始遍历,因此用于随机访问则效率比较低,但是插入元素时不需要对数据进行移动,因此插入效率较高。同时,LinkedList 是非线程安全的容器。

那么,在实际使用时,如何从这几种容器中选择合适的使用呢?当对数据的主要操作为索引或只在集合的末端增加、删除元素时,使用 ArrayList 或 Vector 效率比较高;当对数据的操作主要为指定位置的插入或删除操作时,使用 LinkedList 效率比较高;当在多线程中使用容器时(即多个线程会同时访问该容器),选用 Vector 较为安全。

常见笔试题:

1.若线性表最常用的操作是存取第 i 个元素及其前趋的值,则采用( )存储方式节省时间。

A.单链表 B.双链表 C.单循环链表 D.顺序表

答案:D。顺序适合在随机访问的场合使用,访问时间复杂度为 O(1),而列表的随机访问操作的时间复杂度为 O(n)。


4.9.4 HashMap、Hashtable、TreeMap 和 WeakHashMap 有哪些区别

Java 为数据结构中的映射定义了一个接口 java.util.Map,它包括 3 个实现类:HashMap、Hashtable 和 TreeMap。Map 是用来存储键值对的数据结构,在数组中通过数组下标来对其内容索引的,而在 Map 中,则是通过对象来进行索引,用来索引的对象叫做 key,其对应的对象叫做 value。

HashMap 是一个最常用的 Map,它根据键的 HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。由于 HashMap 与 Hashtable 都采用了 hash 法进行索引,因此二者具有许多相似之处,它们主要有如下的一些区别:

1)HashMap 是 Hashtable 的轻量级实现(非线程安全的实现),它们都完成了 Map 接口,主要区别在于 HashMap 允许空(null)键值(key)(但需要注意,最多只允许一条记录的键为 null,不允许多条记录的值为 null),而 Hashtable 不允许。

2)HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsvalue 和 containsKey,因为 contains 方法容易让人引起误解。Hashtable 继承自 Dictionary 类,而 HashMap 是 Java 1.2 引进的 Map interface 的一个实现。

3)Hashtable 的方法是线程安全的,而 HashMap 不支持线程的同步,所以它不是线程安全的。在多个线程访问 Hashtable 时,不需要开发人员对它进行同步,而对于 HashMap,开发人员必须提供额外的同步机制。所以,就效率而言,HashMap 可能高于 Hashtable。

4)Hashtable 使用 Enumeration,HashMap 使用 Iterator。

5)Hashtable 和 HashMap 采用的 hash/rehash 算法都几乎一样,所以性能不会有很大的差异。

6)在 Hashtable 中,hash 数组默认大小是 11,增加的方式是 old×2+1。在 HashMap 中,hash 数组的默认大小是 16,而且一定是 2 的指数。

7)hash 值的使用不同,Hashtable 直接使用对象的 hashCode。

以上 3 种类型中,使用最多的是 HashMap。HashMap 里面存入的键值对在取出时没有固定的顺序,是随机的。一般而言,在 Map 中插入、删除和定位元素,HashMap 是最好的选择。由于 TreeMap 实现了 SortMap 接口,能够把它保存的记录根据键排序,因此,取出来的是排序后的键值对,如果需要按自然顺序或自定义顺序遍历键,那么 TreeMap 会更好。LinkedHash-Map 是 HashMap 的一个子类,如果需要输出的顺序和输入的相同,那么用 LinkedHashMap 可以实现,它还可以按读取顺序来排列。

WeakHashMap 与 HashMap 类似,二者的不同之处在于 WeakHashMap 中 key 采用的是「弱引用」的方式,只要 WeakHashMap 中的 key 不再被外部引用,它就可以被垃圾回收器回收。而 HashMap 中 key 采用的是「强引用的方式」,当 HashMap 中的 key 没有被外部引用时,只有在这个 key 从 HashMap 中删除后,才可以被垃圾回收器回收。

常见笔试题:

1.在 Hashtable 上下文中,同步指的是什么?

答案:同步意味着在一个时间点只能有一个线程可以修改 hash 表,任何线程在执行 Hash-table 的更新操作前都需要获取对象锁,其他线程则等待锁的释放。

2.如何实现 HashMap 的同步?

答案:HashMap 可以通过 Map m=Collections.synchronizedMap(new HashMap())来达到同步的效果。具体而言,该方法返回一个同步的 Map,该 Map 封装了底层的 HashMap 的所有方法,使得底层的 HashMap 即使是在多线程的环境中也是安全的。

4.9.5 用自定义类型作为 HashMap 或 Hashtable 的 key 需要注意哪些问题

HashMap 与 Hashtable 是用来存放键值对的一种容器,在使用这两个容器时有一个限制:不能用来存储重复的键。

从表面上看,向 HashMap 中添加的两个键值对的 key 值是相同的,可是为什么在后面添加的键值对没有覆盖前面的 value 呢?为了说明这个问题,下面首先介绍 HashMap 添加元素的操作过程。具体而言,在向 HashMap 中添加键值对 <key,value> 时,需要经过如下几个步骤:首先,调用 key 的 hashCode()方法生成一个 hash 值 h1,如果这个 h1 在 HashMap 中不存在,那么直接将 <key,value> 添加到 HashMap 中;如果这个 h1 已经存在,那么找出 HashMap 中所有 hash 值为 h1 的 key,然后分别调用 key 的 equals()方法判断当前添加的 key 值是否与已经存在的 key 值相同。如果 equals()方法返回 true,说明当前需要添加的 key 已经存在,那么 HashMap 会使用新的 value 值来覆盖掉旧的 value 值;如果 equals()方法返回 false,说明新增加的 key 在 HashMap 中不存在,因此会在 HashMap 中创建新的映射关系。当新增加的 key 的 hash 值已经在 HashMap 中存在时,就会产生冲突。一般而言,对于不同的 key 值可能会得到相同的 hash 值,因此就需要对冲突进行处理。一般而言,处理冲突的方法有开放地址法、再 hash 法、链地址法等。HashMap 使用的是链地址法来解决冲突,具体操作方法如图 4-13 所示。

向 HashMap 中添加元素时,若有冲突产生,其实现方式如图 4-14 所示。

从 HashMap 中通过 key 查找 value 时,首先调用的是 key 的 hashCode()方法来获取到 key 对应的 hash 值 h,这样就可以确定键为 key 的所有值存储的首地址。如果 h 对应的 key 值有多个,那么程序接着会遍历所有 key,通过调用 key 的 equals()方法来判断 key 的内容是否相等。只有当 equals()方法的返回值为 true 时,对应的 value 才是正确的结果。

在上例中,由于使用自定义的类作为 HashMap 的 key,而没有重写 hashCode()方法和 e-quals()方法,默认使用的是 Object 类的 hashCode()方法和 equals()方法。Object 类的 equals ()方法的比较规则如下:当参数 obj 引用的对象与当前对象为同一个对象时,就返回 true,否则返回 false。hashCode()方法会返回对象存储的内存地址。由于在上例中创建了两个对象,虽然它们拥有相同的内容,但是存储在内存中不同的地址,因此在向 HashMap 中添加对象时,调用 equals()方法的返回值为 false,HashMap 会认为它们是两个不同的对象,就会分别创建不同的映射关系,因此为了实现在向 HashMap 中添加键值对,可以根据对象的内容来判断两个对象是否相等,这就需要重写 hashCode()方法和 equals()方法,示例如下:

由此可以看出,开发者在使用自定义类作为 HashMap 的 key 时,需要注意以下几个问题:

1)如果想根据对象的相关属性来自定义对象是否相等的逻辑,此时就需要重写 equals()方法,一旦重写了 equals()方法,那么就必须重写 hashCode()方法。

2)当自定义类的多项作为 HashMap(Hashtable)的 key 时,最好把这个类设计为不可变类。

3)从 HashMap 的工作原理可以看出,如果两个对象相等,那么这两个对象有着相同的 hashCode,反之则不成立。


4.9.6 Collection 和 Collections 有什么区别

Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。实现该接口的类主要有 List 和 Set,该接口的设计目标是为各种具体的集合提供最大化的统一的操作方式。

Collections 是针对集合类的一个包装类,它提供一系列静态方法以实现对各种集合的搜索、排序、线程安全化等操作,其中大多数方法都是用来处理线性表。Collections 类不能实例化,如同一个工具类,服务于 Collection 框架。若在使用 Collections 类的方法时,对应的 collec-tion 的对象为 null,则这些方法都会抛出 NullPointerException。

============================

end

发布了101 篇原创文章 · 获赞 20 · 访问量 6万+

Guess you like

Origin blog.csdn.net/qq_40993412/article/details/104059813