1.ArrayList和Vector的区别
这两个类都实现了List接口(List 接口继承了Collection接口),它们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当一种动态的数组,我们以后可以按位置索引号取出某个元素,并且其中的数据是允许重复的,这是HashSet
之类的集合的最大不同处,HashSet
之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素(本来题目问的与HashSet
没有任何关系,但为了说清楚ArrayList
和Vector
的功能,我们使用对比方式,更有利于说明问题。)接着才说ArrayList
和Vector
的区别,主要包括两个方面。
-
同步性:
Vector
是线程安全的,也就是说它的方法之间是线程同步的,而ArrayList
是线程不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那么最好是使用ArrayList
,因为它不考虑线程安全,效率会比较高;如果有多个线程会访问到集合,那最好是使用Vector
,因为不需要我们自己再考虑和编写线程安全的代码。 -
数据增长:
ArrayList
与Vector
都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList
与Vector
的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector
默认增长为原来的两倍,而ArrayList
的增长策略在文档中没有明确规定(从源代码看到的时增长为原来的1.5倍)。ArrayList
与Vector
都可以设置初始的空间大小,Vector
还可以设置增长的空间大小,而ArrayList
没有提供设置增长空间的方法。总结: 即
Vector
增长原来的一倍,ArrayList
增加原来的0.5倍。
2.说说ArrayList
、Vector
、LinkedList
的存储性能和特性。
ArrayList
和 Vector
都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector
由于使用了synchronized方法(线程安全),通常性能上较ArrayList
差,而LinkedList
使用双向链表实现存储,按序号索引数据通常需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
ArrayList
在查找时速度快,LinkedList
在插入与删除时更具优势。
3.快速失败(fail - fast) 和 安全失败(fail - safe) 的区别是什么?
Iterator 的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util
包下面的所有集合都是快速失败的,而java.util.concurrent
包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException
异常,而安全失败的迭代器永远不会抛出这样的异常。
4.HashMap的数据结构
在Java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap
也不例外。HashMap
实际上是一个数组和链表的结合体(在数据结构中,一般称之为"链表散列")
5.HashMap的工作原理是什么?
Java中的HashMap
是以键值对(key-value)的形式存储元素的。HashMap
需要一个hash函数,它使用hashCode()
和equals()
方法来向集合/从集合添加和检索元素。当调用put()
方法的时候,HashMap
会计算key 的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。HashMap
的一些重要的特性是它的容量(capacity),负载因子(load factor) 和扩容极限(threshold resizing)。
6.HashMap什么时候进行扩容呢?
当HashMap
中的元素个数超过数组大小 loadFactor
时,就会进行数组扩容,loadFactor
的默认值为0.75,也就是说,默认情况下,数组大小为16.那么当HashMap
中元素个数超过16 * 0.75 = 12 的时候,就把数组的大小扩展为2 * 16 = 32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap
中元素的个数,那么预设元素的个数能够有效的提高HashMap
的性能。
比如说,我们有 1000 个元素 new HashMap(1000)
,但是理论上来讲 new HashMap(1024)
更合适,不过上面已经说过,即使是 1000,HashMap
(容量:2的n次方)也自动会将其设置为 1024。 但是 new HashMap(1024)
还不是更合适的,因为 0.75*1024 < 1000, 也就是说为了让 0.75 * size > 1000, 我们必须这样 new HashMap(2048)
才最合适,既考虑了loadFactor
的问题,也避免了resize
的问题.