zoukankan      html  css  js  c++  java
  • 面试题-Java集合(新更新版本)

    前言

    Java集合部分的题目,是我根据Java Guide的面试突击版本V3.0再整理出来的,其中,我选择了一些比较重要的问题,并重新做出相应回答,希望对大家起到一定的帮助。

    Java集合

    1. 说说Arraylist 与 LinkedList 区别?

      • 底层数据结构:ArrayList是数组,LinkedList是链表,那么问题就变成了数组和链表这两种数据结构的区别
      • 增删、查的平均时间复杂度:
        • 插入和删除(注意,这里的插入和删除并不包括查找,仅仅看操作本身的时间复杂度。另外,下面讨论的前提是需要维护数组有序。
          • 数组如果插(删除)在尾部,这种情况是最优时间复杂度,为O(1),如果插(删除)在头部,这种情况是最差时间复杂度,为O(N);平均时间复杂度为 (1+2+3+...n)n/2 = O(N)。
            • 注意:如果数组是无序的,完全可以把待插入数据和插入位置的数据交换一下,实现O(1)的时间复杂度。
          • 链表插入(删除)的时间复杂度,最好最差和平均都是O(1)
        • 查找
          • 数组根据下标的随机查找,最好最坏平均都是O(1)
          • 链表根据下标的随机查找,最好是O(1),最坏是O(N),平均为O(N)
            • JAVA实现中优化了链表根据下标查找的过程,先判断待查找的索引下标是在前半段还是后半段,如果在前半段,就从头开始查;如果在后半段,就从尾开始查。
          • 数组和链表,根据值查找,都需要遍历,时间复杂度都为O(N)
      • 空间复杂度:
        • 链表需要额外存储指针数据,数组不需要,但是JAVA实现中会冗余一些数组位置,也增加了空间复杂度。
    2. 说⼀说 ArrayList 的扩容机制

      • 扩容原理:ArrayList的add方法,在真正add之前,会检查是否需要扩容,扩容的关键就是确定新的数组长度,java源码中是按照原始长度的1.5倍来确定新长度的。具体的拷贝过程,就是建立一个新的长度的数组,把原始数组中的数据拷贝到新数组中
      • 最佳实践:在已知需要加入list中的元素个数时,可以调用ensureCapacity方法来提前扩容到指定的大小,避免添加的过程中不断扩容,提高性能
    3. HashMap和Hashtable的区别?

      • 线程安全性和性能:HashTable使用synchronized加锁,线程安全,但是性能较差
      • Nullkey和NullValue的支持:HashTable中key和value都不能为null,如果为空,直接抛出空指针异常;HashMap中支持为null的key,也支持为null的value
    4. HashMap和HashSet的区别?

      • HashSet底层用的就是HashMap实现的,key存储实际的对象,value存储一个默认的Object
    5. 说一说HashMap的底层数据结构

      • JDK1.8之前,HashMap的底层数据结构是数组+链表
      • JDK1.8之后,Java优化了HashMap的链表部分,当链表达到默认阈值8时,会转变为红黑树,提高搜索效率,等值查询的平均时间复杂度从链表的O(N)变为红黑树的O(logN)
    6. HashMap的扩容机制

      • 和ArrayList类似,初始都是一个空的数组,当实际添加数据时,会初始化一个默认长度为16的数组
      • 负载因子:HashMap的扩容依据 是当当前容器中的键值对个数 大于 数组长度×负载因子=负载个数时,进行扩容,扩容为之前长度的2倍。
    7. HashMap的长度为什么是2的幂次方

      • hash值是int类型的,默认有很大的范围,但是数组又不可能那么大,所以需要按照数组的实际大小取模
      • 位运算的效率高于取模的效率,所以要尽可能转化为位运算。
        • 当长度为2的幂次方时,h%length取模的操作可以转化为h&(length-1)
    8. HashMap 多线程操作导致死循环问题

      这个问题的关键就是在rehash的过程中,多线程导致环形链表。HashMap本身就是线程不安全的,多线程的情况下应该使用ConcurrentHashMap。

    9. ConcurrentHashMap 和 Hashtable 的区别?

      这两个数据结构主要区别就在于实现线程安全的方式不同。

      • 在jdk1.7的时候,concurrentHashMap底层使用的是分段锁的概念,和HashTable比提高了并发度
      • 在jdk1.8之后,摒弃了分段锁的概念,使用synchronized加CAS来实现线程安全,synchronized只锁当前链表或者红黑树的头节点,效率和分段锁比又大大提升。
    10. comparable 和 Comparator的区别?

      • comparable提供一个compareTo方法,代表了该类可以被比较
      • comparator是一个比较器,方法参数是两个对象,实现两个对象的比较
  • 相关阅读:
    电容
    51单片机
    三极管
    Scala 面向对象(八):特质(接口) 一
    Scala 面向对象(七):静态属性和静态方法
    Scala 面向对象(六):面向对象的特征二:继承 (一)
    Scala 面向对象(五):面向对象的特征一:封装性
    Scala 面向对象(四):import
    Scala 面向对象(三):package 包 (二)
    Scala 面向对象(二):package 包 (一) 入门
  • 原文地址:https://www.cnblogs.com/ging/p/13467961.html
Copyright © 2011-2022 走看看