1)ArrayList 和 Vector 的区别。
答:
ArrayList
1、实现原理:采用动态对象数组实现,默认构造方法创建了一个空数组
2、第一次添加元素,扩展容量为10,之后的扩充算法:原来数组大小+原来数组的一半
3、当插入、删除位置比较靠前时,与链表比较,不适合进行删除或插入操作
4、为了防止数组动态扩充次数过多,建议创建ArrayList时,给定初始容量
5、多线程中使用不安全,适合在单线程访问时使用,效率较高
Vector
1、实现原理:采用动态数组对象实现,默认构造方法创建了一个大小为10的对象数组
2、扩充的算法:当增量为0时,扩充为原来的2倍,当增量大于0时,扩充为原来大小+增量
3、当插入、删除位置比较靠前时,与链表比较,不适合删除或插入操作
4、为了防止数组动态扩充次数过多,建议创建Vector时,给定初始容量
5、线程安全,适合在多线程访问时使用,效率较低
集合的使用注意:
若使用集合来存储多个不同类型的元素(对象),那么在处理时会比较麻烦
在实际开发中不建议这样使用,我们应该在一个集合中存储相同的类型对象
(2)说说 ArrayList,Vector, LinkedList 的存储性能和特性。
1、ArrayList采用的是数组形式来保存对象的,这种方式将对象放在连续的位置中,所以最大的缺点就是插入删除时非常麻烦
2、LinkedList采用的将对象存放在独立的空间中,而且在每个空间中保存下一个链接的索引,但是缺点就是查找非常麻烦,要从第一个索引开始
3、ArrayList和Vector都是用数组方式存储数据,此数组元素数要大于实际的存储空间以便进行元素增加和插入操作,他们都允许直接用序号索引元素,但是插入数据元素涉及到元素移动等内存操作,所以索引数据快而插入数据慢
4、Vector使用了synchronized方法(线程安全),所以在性能上比ArrayList要差些
5、LinkedList使用双向链方式存储数据,按序号索引数据需要向前或向后遍历数据,索引索引数据慢,插入数据时只需要记录前后项即可,所以插入的速度快
(3)快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么?
1、快速失败(fail-fast)
在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行修改(增加、删除、修改),则会抛出Concurrent Modification Exception.
原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个modCount变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
注意:这里异常的抛出条件是检测到modCount!=expectedmodCount这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。
场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。
2、安全失败(fail-safe)
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。
缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的
场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。
(4)hashmap 的数据结构。
数组+链表(Java7之前包括Java7)
数组+链表+红黑树(从Java8开始)
这里的红黑树与链表都是链式结构
HashMap内部维护了一个数组,数组中存放链表的链首或红黑树的树根
当链表长度超过8时,链表就转换为红黑树,利用红黑树快速增删改查的特点提高HashMap的性能,在红黑树节点数量小于6时,红黑树转变为链表。
(5)HashMap 的工作原理是什么?
HashMap基于hashing原理,我们通过put()和get()方法存储和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来存储值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会存储在链表的第一个节点,链接原先的对象节点,HashMap在每个链表节点中存储键值对对象。