Java集合相关面试题整理

1、为什么要使用集合?

        针对于数组的缺点出现的:数组的长度固定的,且只能存放一种类型的数据;

2、集合的特点?

        (1)长度可扩展,可以存放多种类型的数据;

        (2)只能存放引用类型的数据,哪怕存放基本类型进去,也会先将其转换为包装类型才存储进去;

        (3)集合存放的只是对象的引用,对象本身还是存储在堆中的;

        (4)有俩个基本的接口,iterator接口(collection是list与set的父接口)与map;

           ps:继承顺序list、set ----> collection ----> iterable(其中分装了iterator接口)

3、List集合相关问题:

        (1)List接口的典型实现:

                      1>、ArratList:底层是数组,随机获取元素快,删除、添加慢,线程不安全;

                      2>、vector:底层为数组,随机获取元素快,删除,添加慢,线程安全;

                      3>、LinkedList:底层为链表结构,随机获取元素慢,新增、删除元素较快,线程不安全的;

        (2)ArrayList与LinkedList的区别?(此处只讲随机获取元素以及新增删除方面的异同)

                      ArrayList采用的是数组的方式实现List接口的,数组是采用一段连续的存储单元来存储数据,它的优点是若通过索引的方式快速获定位对象的位置,但是若是新增/删除数据速度会比较慢,因为需要移动所有元素的存储的位置;

                      LinkedList采用的是链表的方式实现List接口的,对于线性链表来说,新增或者删除数据只需要处理节点间的引用就行(线性链表讲解:https://mp.csdn.net/mdeditor/83628312#),但是对于随机得到元素来说速度很慢,因为采用的是链表,故先要遍历链表;

       (3)ArrayList与Vector的区别?

                     1>、ArrayList是线程非安全的,Vector是线程安全的;

                     2>、ArrayList的中的元素如果超过其容量的话,其容量会扩容50%+1,但是Vector却会翻倍;

      (4)数组与链表异同?

                   相同点: 数组是线性的,链表也是线性的;数组的访问是通过索引来访问的,链表型数据的访问是通过移动指针,且只能从头到尾;

                    不同点:数组元素在内存中是连续的,在栈区,而链表元素在内存中是不连续的,在堆区;

4、Set集合的相关问题:

       (1)Set接口的典型实现

                    1>、hashSet:底层采用hash算法,不保证元素的添加顺序,查询效率高(原因见:);

                    2>、LinkedHashSet:hashSet的子类,在hashSet的基础上实现了链表结构,及保证了元素的添加顺序,整体性能低于hashSet(随机访问元素效率慢);

                    3>、TreeSet:不能存储null,底层实现了红黑树算法,有序,擅长于范围查询;

      (2)hashSet与hashMap的关系?

                    1>、hashSet相当于(key,null)的hashMap;

      (3)hashSet、LinkedHashSet的区别与TreeSet的区别?

                    hashSet与LinkedHashSet的区别仅在后者的底层实现了线性链表(按照插入的顺序排序);

                    hashSet与TreeSet的区别:

                            1>、hashSet的key可以为null,但是TreeSet不行;

                            2>、hashSet不能保证插入的元素的顺序,treeSet是有序的(自己的算法排序);

                            3>、hash底层实现的是hash表算法,而TreeSet实现的是红黑树算法;

                            4>、hashSet是通过equals与hashCode方法判断元素是否重复,TreeSet是通过comparato的返回值来判断元素是否重复以及排序的规则的;

                            5>、TreeSet存储自定义类型的对象,自定义的类必须实现comparato方法,否则无法判断元素的“大小”(排序规则);

                            6>、comparato的返回值为0,则不存储元素,返回值为1,则认为存储值与比较值相比较大,若返回值为-1则认为,存储值与比较值相比较小;

                            7>、TreeSet的排序规则分为俩种,自然排序与定制排序,自然排序就是按照从小到大的顺序排序,定制排序则是按照自己的规则排序;

5、Map集合的相关问题:

     (1)Map集合的典型实现

                1>、HashMap:底层采用hash表算法,key的顺序与hashSet一致,不会保证添加的顺序;

                2>、TreeMap:底层红黑树算法,排序规则按照自然排序或者定制顺讯;

                3>、LinkedHashMap:采用链表算法和哈希算法,保证元素的添加顺序;

                4>、HashTable:采用哈希表算法,基本功能与hashMap类似,但是会保证插入的顺序,且为线程同步的,key键不能为null,且效率低下(一个线程对其做put处理时,其他线程不仅不嫩使用put且不能使用get,造成线程的阻塞)jdk5之后提供了ConcurrentHashMap,是HashTable的扩展版本;

                5>、Properties:HashTable的子类,用来加载properties文件的;

     (2)HashMap与HashTable的区别?

                 1>、俩者几乎相同,但是会保证插入的顺序(且不能保证随着时间的推移,元素顺序不变),且为线程同步,jdk5之后出了ConcurrentHashMap,是HashTable的扩展;

                 2>、HashMap使用的迭代器是Iterator是fail-fast(但是其remove方法是不会抛出fail-fast,且不是必然发生的),而HashTable使用的enumerator迭代器不是fail-fast的;

                 3>、HashMap在单线程的性能要超过HashTable;

      (3)HashMap的实现原理?

                  1>、map集合:

                             严格意义上来说map并不是集合,而是俩个集合之间的映射关系;

                             并未实现collection接口也未实现Iterable接口,因此不能采用forEach遍历;

                             是Entry(key,value),map可以看成是由多个Entry组成的;

                  2>、HashMap的实现原理:

                             是基于哈希表算法+数组实现的;

                             HashMap在存储对象时是将key-value当做一个整体进行处理的,这个整体就是一个Node对象,保存对象时,先调用key的hash算法来决定其在数组中的位置,在根据equals算法决定其在该数组链表(bucket)上的位置;取对象时,先得到key的hashCode值,在根据equals方法从该位置上的链表中取出该Node;

                              使用了fail-fast机制;

                 3>、Map与set的关系?

                               hashSet、hashMap采用的底层算法都是hash表算法,treeSet与treeMap采用的都是红黑树算法;

                               set集合就是由map集合的key组成的;

       (4)ConcurrentHashMap

                同步机制:使用分段锁技术------结构与HashMap类似,采用的是数组+链表的方式,分段锁是将集合分为一段一段的segment然后给每一段segment分配一个锁,当一个县城访问一个segment时,其他的分段也能被其他线程访问,即可以实现并行插入;

                组成结构:一个ConcurrentHashMap是一个segment数组,一个segment是一个hashEntry数组,而每个hashEntry都是链表结构的元素,用来封装散列映射表中的键值对;

                应用场景:多线程的写

                             get不加锁,定位到segment之后找到头节点进行去取操作,value是通过volatile修饰的;

                             put加锁,添加到hash链表的头部;

                             remove加锁,由于next是final类型的,所以必须把删除之前的节点都复制一遍;

              ps:ConcurrentHashMap只能保证每一个调用是原子性的,但是不能保证多次的调用也是原子性的(这句话不太懂,如果有人知道的话请指导一下)

                    

猜你喜欢

转载自blog.csdn.net/qq_36959774/article/details/85410772