java面试总结(2)之集合

collection

    -List 单列有序不唯一集合接口
        boolean retainAll(Collection c) 修改调用集合的元素成为他们的交集并返回true,如果他们元素相同,则返回false
        
        -ArrayList
            *底层数据结构是数组默认初始长度10,线程不同步,效率高,查询快,更新慢
            *add之前会校验size+1是否超出数组容量,如果超出会创建一个新数组(大小是老数组容量*3/2+1)作为目标数组,并把老数组的元素全部copy过来
            *ArrayList线程不同步的体现:
                当list的size大小刚好为9的时候,两个线程同时add,可能会出现两个线程校验的size+1都是9+1,没有超出10,那么都不会扩容,当第二个线程add时,list的索引9处实际上已经有了元素,而抛出数组下标越界异常。
                两个线程同时add操作时,同一索引的元素可能会被覆盖。
        
        -LinkedList
            *底层数据结构是双向链表,线程不同步,效率高,更新快,查询慢
        
        -Vector
            *底层数据结构是数组,线程同步,效率低,查询快,更新慢
        
        -Stack
            *Vector的子类,具有栈的特性,先进后出,通过push(E item)方法把元素压入栈底

    -Set 单列无序唯一集合接口


        -HashSet
            *无序唯一,底层维护的是一个hashmap,所有的元素都是存储在hashmap的key中,而value中存储的是一个默认的Object常量
            *插入元素的时候其实是调用hashmap的put方法,因hashmap保证key的唯一性而hashset也具有唯一性
            *hashset中存储的元素最好重写equals和hashcode方法,以提高效率
        
        -LinkedHashSet
            *继承自HashSet,底层维护一个linkedhashmap

        -TreeSet
            *有序且唯一的单列集合类,底层维护的是一个treemap

    -Queue 
        *java提供的队列接口,linkedlist就实现了该接口


Map

    -HashMap

        *底层数据结构是数组和hash表,线程不同步
         不同步体现在:
             两个线程同时put时发生了碰撞(既key的hashcode相同),那么会把另一个线程put的key-value覆盖
                 两个线程同时put时碰撞的过程:
                    假设map中数组有个entryA
                    线程一put的是entryB
                    线程二put的是entryC
                    恰好B和C的Hashcode都和A的相同,那么B和C会put到与entryA相同索引位置上,但是B和C之间因为不同线程的隔离,所以会覆盖另一方
            当重新调整HashMap容量的时候,如果发生两个线程同时调整HashMap的默认容量,会导致死循环的发生    
         解决方案:
             jdk5+使用ConcurrentHashMap
             通过Collections.synchronizedMap(Map map)方法返回一个当前map加同步锁的map对象
              
        *hashmap默认的负载因子(load factor)大小是0.75,也就是说,如果map的当前size超过默认容量(initialCapacity=16)*负载因子(0.75),那么会重新创建一个原来容量2倍的数组

        *之所以使用String类型作为map的键是因为重写了hashcode和equals方法,因为不同的hashcode可以避免碰撞。并且是final类型的,当一个对象作为键插入到map中,如果该对象发生改变,那么将无法获取到map中该对象作为键的entry

        *什么是hashmap碰撞,hashmap的底层是一个由多个entry链表组成的entry数组,每一个entry都有对应的hashcode,如果两个entry的hashcode相同,就会调用equals比较两个entry的key是否相同(这个过程称为碰撞),如果不同,那么这两个entry就会形成一个entry链表。所以保证hashcode的唯一性,即可避免碰撞,也就是一个entry链表只有一个entry这样map的效率将会大大提高

        *如果要使用对象作为键,必须重写对象的hashcode和equals方法,最好将对象声明为final类型,既要保证对象再插入map后不可变

    -LinkedHashMap
        *继承自hashmap,线程不同步,底层维护了一个双向链表,以保证迭代和插入顺序的一致性,以及链表的更新快的特性

    -TreeMap
        *底层基于红黑树算法实现(二叉树的一种)、有序且唯一、线程不同步、作为TreeMap键的对象应该实现Comparable或Comparator接口,注意key为null只能存一个元素,否则抛空指针

    -ConcurrentHashMap
        *线程同步,多线程下替代hashmap的最佳选择,注意key或value为null会抛空指针

    -HashTable
        *和HashMap一样也是一个hash表,线程同步,注意key或value为null会抛空指针(已被HashMap取代)

    


 

猜你喜欢

转载自blog.csdn.net/m0_37414960/article/details/81329848