Java从入门到入土之集合篇

集合学习笔记

  • 概述
    • Collection接口:
    • Set接口:
    • Queue接口:
    • Map接口:

概述

Collection是集合层次结构中的根界面,依赖于 Iterator,Map接口。
Collection下有3个重要子接口:List,Set,Queue。
Java从入门到入土之集合篇_第1张图片

Collection接口:

List:有序集合(也称为序列 )几个重要实现类:

  1. Arraylist: 底层使用动态数组实现。我们知道数组的长度一旦申请就无法改变,ArrayList是在数组内的负载因子(数组已用的值/数组长度)达到1时进行扩容,扩容的方式是申请一个新的数组讲旧数组的数据全部复制到新的数组中,然后销毁旧数组。ArrayList的扩容增量是0.5+1,例如:旧数组的长度为10,扩容后的数组长度为16。注意一点,当我们实例化一个ArrayList的时候如果不给于他一个长度,会默认长度为10。;
    优点:因为底层是数组,数据在数组中有下标,通过下标取值速度很快,查询数据的速度快,效率高。
    缺点:每一次对数组的增加和删除操作会使操作位置后面的元素移动,增删速度慢,并且非线程安全。
  2. **Vector:**底层同样采用动态数组实现。加载因子也是1,扩容增量为1,例如:旧数组的长度为10,扩容后的数组长度为20;默认长度也是10。
    优点:查询速度快,线程安全。
    缺点:增删操作速度慢,效率低。
  3. **LinkedList:**底层采用双向链表的数据结构,链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,双向链表是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表;
    Java从入门到入土之集合篇_第2张图片优点:链表的增删操作只需要在操作位置断开指针的指向,将前驱或后驱重新指向新的元素,所以增删操作速度快,效率高。
    缺点:链表的查询需要从头部依次查找,查询速度很慢。非线程安全

Set接口:

Set:无序集合(不包含重复元素的集合)几个重要实现类:

  1. HashSet: 底层使用HashMap存储数据,采用哈希表的数据结构。在HashSet中,元素都存到HashMap键值对的Key上面,而Value时有一个统一的值private static final Object PRESENT = new Object();,(定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。),依靠从写hashCode()和equals()两个方法保证元素的不重复()。加载因子为0.75,扩容增量为1。实例化默认大小为16.
    HashSet是非线程安全,并且可以存放一个null。
  2. **LinkedHashSet:**继承HashSet,继承HashSet未开放的构造器,操作方法与HashSet类似,与HashSet的区别在于LinkedHashSet基于LinkedHashMap保存数据,维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序,数据结构采用的哈希表和双重链表。与HashSet相同,加载因子为0.75,扩容增量为1。实例化默认大小为16.
    也是非线程安全,可以存放一null。
  3. **TreeSet:**是一个有序的集合类,TreeSet的底层是通过TreeMap实现的,采用红黑树数据结构。TreeSet并不是根据插入的顺序来排序,而是根据实际的值的大小(或自定义顺序)来排序。
    非线程安全,元素不允许为null。

Queue接口:

Queue用于模拟队列这种数据结构,队列通常是指“先进先出”(FIFO)的容器。新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素。通常,队列不允许随机访问队列中的元素。Queue接口下面的实现类是PriorityQueue,子接口是Deque,Deque接口的实现类ArrayDeque,同时Deque还被LinkedList类实现,LinkedList在之前被用作实现队列。

  1. LinkedList: 上面说过了。
  2. PriorityQueue: PriorityQueue是一个比较标准的队列实现类。原因是PriorityQueue保存队列元素的顺序并不是按照加入队列的顺序,而是按照队列元素的大小进行重新排序。因此当调用peek()或者是poll()的方法取出队列中的元素通常都是最小的元素。注意的是peek()方法取出队列头部元素时候,不删除该元素,而poll()方法取出元素时会删除元素。如果遇到队列为空的情况是,两者都会返回null。
    数据结构也是采用的动态数组。
    PriorityQueue也不是根据插入的顺序来排序,而是根据实际的值的大小(或自定义顺序)来排序。
    非线程安全,元素不允许为null。
  3. Deque接口: Deque接口是Queue接口的子接口,它代表一个双端队列。双端队列即两端都可以执行进出操作。相对于Queue增加了很多方法,而且可以被当成栈来使用,因为该类里还包含了pop(出栈)、push(入栈)两个方法。
    同样基于数组实现。
  4. ArrayDeque: ArrayDeque就是用数组实现的Deque,ArrayDeque为了满足可以同时在数组两端插入或删除元素的需求,其内部的动态数组还必须是循环的,即循环数组(可以看成是首尾相连带有下标的数组)。ArrayDeque维护了两个变量,表示ArrayDeque的头head和尾tail。当向头部插入元素时,head下标减一然后插入元素。而 tail表示的索引为当前末尾元素表示的索引值加一。若当向尾部插入元素时,直接向tail表示的位置插入,然后tail再加一。当head==tail时即达到数组上限,扩容后将数据按照下标复制到新数组,复制分两次进行,第一次复制head右边的元素,第二次复制head左边的元素。
    ArrayDeque是非线程安全的。 当作为栈使用时,性能比Stack好;当作为队列使用时,性能比LinkedList好,元素不允许为空。

Map接口:

Map:(键值对存储数据)几个重要实现类:

  1. HashMap: 根据键的hashCode值存储数据,采用哈希表存(数组链表)数据结构,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 加载因子为0.75,扩容增量为1,默认大小为16(16=1<<4,运行与查找速度快,要求大小为2的幂)。
    HashMap是非线程安全的,允许且只能一个null作为键,值允许有多个为null。
  2. LinkedHashMap: LinkedHashMap是HashMap的一个子类。LinkedHashMap中可以保持两种顺序,分别是插入顺序和访问顺序,这个是可以在LinkedHashMap的初始化方法中进行指定的,默认是按照插入顺序进行编排。在LinkedHashMap中,是通过双向链表的结构来维护节点的顺序的,每个节点都进行了双向的连接,维持插入的顺序(默认)。加载因子为0.75,扩容增量为1,默认大小为16。
    LinkedHashMap是非线程安全的,允许且只能一个null作为键,值允许有多个为null。
  3. TreeMap: 它是一个有序集合,而且是一个红黑树结构,每个key-value都作为一个红黑树的节点。如果在调用TreeMap的构造函数时没有指定比较器,则根据key执行自然排序(因为是有序的)。
    TreeMap是非线程安全的,(默认比较器)不允许键为null,允许值为null。
  4. Hashtable: Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(加载因子)时,同样会自动增长。加载因子为0.75,扩容增量为2+1,例如 :HashTable的容量为11,一次扩容后是容量为23;默认大小为11.HashTable于HashMap类似,都是采用链表方式解决哈希冲突。区别在于,HashTable的键与值都不允许为null,对容器的基础大小无要求。并且HashTable是线程安全的
    Hashtable是线程安全的,键与值都不允许为null。

你可能感兴趣的:(Java从入门到入土之集合篇)