1.什么是集合

集合就是一组用于存储数据的容器,任何集合框架都包含三大块内容:对外的接口、接口的实现和集合运算的算法

  • 对外的接口:表示接口的抽象数据类型。接口允许我们操作集合时不必关注具体实现,从而达到多态。在java中,接口通常用来定义规范
  • 接口的实现:对数据结构进行一个封装
  • 算法:在一个实现来某个集合框架中的接口对象身上完成某种算法,例如查找、排序等。这些算法通常是多态的,因为相同的算法可以在一个接口上被不同的实现

    2.集合特点

  • 存储对象:对象封装数据,对象多了也需要存储。集合用于存储对象

  • 可变长度:对象的个数确定可以使用数组,对象的个数不确定的可以用集合

    3.集合和数组的区别

  • 数组是固定长度的;集合是可变长度的

  • 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型
  • 数组存储的元素必须是同一数据类型;集合存储的对象可以是不同数据类型

    4.使用集合框架的好处

  • 容量自动增长

  • 提供来高性能的数据结构和算法,使编码更轻松,提高程序速度和质量
  • 允许不同API之间的相互操作,API之间可以来回传递集合;例如list转map等
  • 可以方便的扩展或者改写集合,提高代码复用性和可操作性。
  • 通过使用JDK自带的集合类,可以降低代码维护和学习API成本

    5.常用的集合类有那些

    集合的接口可以分为两大类:Map接口和Collection接口,其他接口都是继承自这两个接口

其中Map接口包含:HashMap、TreeMap、HashTable、ConcurrentHashMap已经Propertites等
Collection接口又包含两个个子接口:Set接口、List接口
Set接口主要实现类有:HashSet、TreeSet、LinkedHashSet等
List接口的实现类主要有:ArrayList、LinkedList、Stack、Vector等
image.png

6.集合底层数据结构

ArrayList和Vector底层是Object数组;LinkedList底层是双向循环链表

HashSet是基于HashMap实现的,底层采用的是HashMap来保存元素,他保存的数据无序并且唯一
LikedHashSet继承自HashSet,并且其内部通过LinkedHashMap实现。他保存的数据有序,并且唯一
TreeSet底层使用的是红黑树,他保存的数据有序且唯一

HashMap在JDK1.8之前由数组+链表组成,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(拉链法)。JDK1.8之后HashMap在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认8)时,将链表转化为红黑树,以减少搜索时间
LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了 一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作, 实现了访问顺序相关逻辑。
HashTable:是由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的
TreeMap底层使用的是红黑树(自平衡的排序二叉树)

7.哪些集合类是线程安全的?

Vector比Arraylist多了同步机制,底层方法采用synchronized保证线程安全,所以效率低,现在已经不建议使用。
Stack是一个堆栈类,采用先进后出策略,在进行出栈入栈操作时候也使用了synchronized进行同步,所以也是线程安全的。
Hashtable相对于HashMap多了synchronized进行线程同步

8.Java集合的快速失败机制 “fail-fast”?

fail-fast机制其实就是一个java集合的安全保护机制,当多个线程并发情况下对一个集合的结构进行改变的时候,可能会产生fail-fast机制
例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素, 在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出ConcurrentModificationException 异常,从而产 生fail-fast机制。
产生原因:
迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用 hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为 expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
解决办法:

  1. 在遍历过程中,所有涉及到改变modCount值得地方全部加上synchronized。
  2. 使用CopyOnWriteArrayList来替换ArrayList

    9.怎么确保一个集合不能被修改?

    可以使用Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java.lang.UnsupportedOperationException异常。
    1. List list = new ArrayList<>();
    2. list. add("x");
    3. Collection clist = Collections. unmodifiableCollection(list);
    4. clist. add("y"); // 运行时此行报错