java面试中集合框架问题汇总

来源:互联网 发布:整形医院网络咨询招聘 编辑:程序博客网 时间:2024/05/18 03:35

                                   java面试中集合框架问题汇总

Java集合框架图一览:
一、ArrayList扩容机制
ArrayList底层采用Object类型的数组实现,当使用不带参数的构造方法生成ArrayList对象时,实际上会在底层生成一个长度为10的Object类型数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */ 
    privatevoidgrow(intminCapacity) { 
        // overflow-conscious code 
        intoldCapacity = elementData.length; 
        intnewCapacity = oldCapacity + (oldCapacity >>1); 
        if(newCapacity - minCapacity <0
            newCapacity = minCapacity; 
        if(newCapacity - MAX_ARRAY_SIZE >0
            newCapacity = hugeCapacity(minCapacity); 
        // minCapacity is usually close to size, so this is a win: 
        elementData = Arrays.copyOf(elementData, newCapacity); 
    
int newCapacity = oldCapacity + (oldCapacity >> 1)
newCapacity 就是扩容的新组数大小。而扩容的大小是根据原有旧数组大小来决定的。
oldCapacity >>1。就是右移1位,这里会换算成二进制来进行。就是把十进制对应的数字换成二进制后往右边移一位。所以跟除以2差不多。所以扩容为原来的1.5倍。
但是右移一位的时候,如果非偶数,也就是说二进制数的最低位为1,则会舍弃,就成为了除2-1。对于CPU而言,右移一位要比除2快很多
二、HashMap为什么线程不安全?

先来了解一下HashMap的底层存储结构,HashMap底层是一个Entry数组,一旦发生Hash冲突的的时候,HashMap采用拉链法解决碰撞冲突,Entry内部的变量:

  1. final Object key;
  2. Object value;
  3. Entry next;
  4. int hash;
通过Entry内部的next变量可以知道使用的是链表,这时候我们可以知道,如果多个线程,在某一时刻同时操作HashMap并执行put操作,而有大于两个key的hash值相同,如图中a1、a2,这个时候需要解决碰撞冲突,而解决冲突的办法上面已经说过,对于链表的结构在这里不再赘述,暂且不讨论是从链表头部插入还是从尾部初入,这个时候两个线程如果恰好都取到了对应位置的头结点e1,而最终的结果可想而知,a1、a2两个数据中势必会有一个会丢失,如图所示:

可以看到扩容方法也不是同步的,通过代码我们知道在扩容过程中,会新生成一个新的容量的数组,然后对原数组的所有键值对重新进行计算和写入新的数组,之后指向新生成的数组。 当多个线程同时检测到总数量超过门限值的时候就会同时调用resize操作,各自生成新的数组并rehash后赋给该map底层的数组table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会有问题。
三、HashMap,put()与get()的复杂度为多少?
默认复杂度都为O(1)
四、HashMap与HashTable与ConcurrentHashMap之间的区别与关系
  1. HashMap不是线程同步、线程不安全,不适合应用于多线程并发环境下,而ConcurrentHashMap是线程安全的集合容器
  2. ConcurrentHashMap的设计有点特别,表现在多个线程操作上。它不用做外的同步的情况下默认同时允许16个线程读和写这个Map容器。因为其内部的实现剥夺了锁,使它有很好的扩展性。不像HashTable和Synchronized Map,ConcurrentHashMap不需要锁整个Map,相反它划分了多个段(segments),要操作哪一段才上锁那段数据。
  3. HashMap与HashTable——HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

原创粉丝点击