• Java 集合面试总结


    1.讲一下Java 中主要有哪些集合

    Java 集合常用的是两种类型的容器,一种是集合Collection  ,另一中是图 Map,存储key-value 键值对

    Collection 又有三个子类型: List 、Set、Queue ,再下面就是抽象类,以及具体的实现.

    常用的是ArrayList, LinkedList ,HashSet , LinkedHashSet ,TreeSet ,HashMap ,LinkedHashMap , TreeMap ,Hashtable


     2. ArrayList 与 LinkedList 的区别

    ArrayList 采用的是数组的形式存储数据,是非线程安全的,也有线程安全的存储是Vector ,在新增元素的方法上加了Synchronized 锁,线程安全但是也降低了效率。

    LinkedList 存储采用的是双向链表的数据结构。在操作增加、删除较多的环境中采用LinkedList 效率较高,在使用下标查询、更新较多的环境中使用ArrayList ,各有优缺点。

    ArrayList 数组结构在存储数据时,未指定容量,默认的容量是 10 ,在增加扩容:是原来长度的1.5倍,使用Arrays.copy() 复制整个数组,相比Vector 则扩容 1 倍

    LinkedList 双向链表,可以头插尾插,因此可以当作队列、栈使用,其没有同步方法,在多线程清空下,使用Collections.synchronizedList ()工具类使其变为同步容器


     3.HashMap 的底层实现

    HashMap 数据结构采用数组+链表的结构存储。存储的过程是根据 key 值获取hash值,再计算下标 index = h%length ,其中length 为数组长度

    若该 index 已经存在值,则发生哈希碰撞。可以通过开放地址法或者拉链法解决冲突。HashMap 中采用的是拉链法解决冲突

    上图是 jdk1.8 才使用的红黑树结构,当碰撞的节点个数到达 8 时,将链表转换为 红黑树结构。同时删除节点小于6时将转换为链表结构

    HashMap 扩容:当数组中存储的容量到达总容量*加载因子(0.75)时,将对数组扩容为原来的 2 倍


    4. HashMap 的容量为何是 2的幂次方倍

    这个是因为计算机的特性决定的,计算机在取余操作是非常慢的,但是按位 & 操作非常快,在计算索引 index = h%length = h &(length - 1),需要的前提条件是 是2的幂次方。 这样加快下标计算


    5.HashMap 扩容是如何被触发的 

     当HashMap 的 size > loadFactory*capacity 即发生扩容,size 是数组节点与链表节点的总和。扩容是一个非常耗费性能的操作,如果数组的长度发生变化,那么所有的节点的索引都需要重新计算。

    jdk 1.8 将此部分进行了优化,在扩容后链表中的元素存储是到过来的,因为是头插的方式。在多线程的情况下要使用 ConcurrentHashMap 容器


    6. HashMap jdk1.7 与 jdk1.8 扩容的区别

    HashMap 为了减少碰撞最好是将元素均匀的分布在每个数组节点,下标的计算直接决定 HashMap 的离散性能

    Hash 算法三部: 取key 的 HashCode 、高位参与运算、取模操作

    这里在第二步:jdk1.8 进行了优化,将hashCode() 的高16位与低16位异或,将更均匀的分布在数组上,同时保证操作不会有较大的开销

    第三步优化:此处取余运算较慢,优化位按位 & 。前提条件就是数组长度length 必须是2的幂次方

    在扩容后插入节点,jdk1.8 中的下标是 index 或者 index+old_length上,好处是不需要重新计算,效率更高

    jdk1.7 使用头插在多线程的条件中,或形成一个环,jdk1.8 没有采用头插的方式,不会出现次情况。如下是jdk1.8 插入


    7.ConcurrentHashMap 使用什么保证线程安全

    ConcurrentHashMap 底层数据结构与HashMap 相同,是多线程安全的

    jdk1.7 采用的是Segment +HashEntity 来进行实现的,jdk1.8 放弃了segment,采用 Node + CAS + synchronized 保证线程安全

    8.ConcurrentHashMap jdk1.7 与1.8 的区别

    jdk1.7 中 ComcurrentHashMap 是Segment 数组与 HashEntity 组成,Segment 将一个大的tabele 分成多个小的table 加锁

    每个Segment 大小默认是 16

    jdk1.8 降低了锁的粒度,jdk 1.7的锁的粒度是 Segment ,内部是HashEntity ,jdk1.8 锁的粒度就是HashEntity

    jdk1.8 中ConcurrentHashMap 因为才有了数据+链表+红黑树的结构,其容量也必须是2的幂次方。默认初始容量 16


     9.遍历Map几种方式

    方式一:遍历Map

    Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) { 
      System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); 
    }

    方式二:遍历key 或者value

    Map<Integer, Integer> map = new HashMap<Integer, Integer>(); 
    //遍历map中的键 
    for (Integer key : map.keySet()) { 
      System.out.println("Key = " + key); 
    } 
    //遍历map中的值 
    for (Integer value : map.values()) { 
      System.out.println("Value = " + value); 
    }

    注意:HashMap 允许key 一个null , HashTable key-value 均不能为null,ConcurrentHashMap key-value 也均不为null

    10.ArrayList 添加与删除元素的方法? 如何对ArrayList 进行排序

    ArrayList 添加的方法 add() ,删除元素的方法 remove()

    集合有排序的方法 sort(Collector<T super E> c) ,需要传入一个比较器,重写compare()方法实现排序

  • 相关阅读:
    fastDFS同步问题讨论
    Android开发(26)--补间动画(Tween)的实现
    android布局
    Linux特殊权限:SUID、SGID、SBIT
    如何使用ssh-keygen生成key
    Linux中环境变量到底写在哪个文件中?解析login shell 和 no-login shell
    使用ssh无密码登录
    github中的ssh配置
    PHP中的一个很好用的文件上传类
    [置顶] js模板方法的思路及实现
  • 原文地址:https://www.cnblogs.com/baizhuang/p/10036573.html
Copyright © 2020-2023  润新知