1、集合框架体系

  • 单列集合

  • 双列集合

2、单列集合

1、Collection接口和常用方法

  • collection接口实现特点

    public interface Collection<E\> extend Iterable<E\>

    1. collection 实现子类可以存放多个元素,每个元素可以是Object

    2. 有些Collection的实现类,可以存放重复元素,有些不可

    3. 有些Collection的实现类,有些是有序的(List),有些不是(Set)

    4. Collection 接口没有直接的实现子类,是通过它的子接口Set和List来实现的

  • 常用方法

    1. add(); 添加单个元素

    2. remove(); 删除指定元素

    3. contains(); 查找元素是否存在

    4. size(); 获取元素个数

    5. isEmpty(); 判断是否为空

    6. clear(); 清空

    7. addAll(); 添加多个元素

    8. containsAll(); 查找多个元素是否都存在

    9. removeAll(); 删除多个元素

2、Collection 接口便利元素方式

  • 使用 Iterator (迭代器)

    1. Iterator 对象称为迭代器,主要用于遍历 Collection 集合中的元素

    2. 所有实现了Collection 接口的集合类都有一个 iterator()方法,用以返回一个实现了Iterator 接口的对象,即可以返回一个迭代器

    3. Iterator 的结构图

      注意:在调用iterator.next() 方法之前必须要调用iterator.hasNext() 进行检测,若不调用,并且下一条记录无效,直接调用iterator.next() 会抛出NoSuchElementException 异常。

    4. Iterator 仅用于遍历集合,Iterator 本省并不存放对象

    5. 当再次使用迭代器时,需要重置迭代器

      iteraator = col.ietrator();

    快捷键:itit

    显示所有快捷键的快捷键:Ctrl + j

  • 增强 for 循环

    增强for循环,可以代替iterator迭代器,特点:增强 for 就是简化版的iterator,本质一样。只能用于遍历集合数组

    • 基本语法

      for (元素类型 元素名: 集合名或数组名) {

      访问元素

      }

    • 快捷键:I

3、List接口

  • 基本介绍

    List 接口时 Collection 接口的子接口

    1. List 集合类中所有元素有序(即添加顺序和取出顺序一致)、且可重复

    2. List 集合中的每个元素都有相应的顺序索引,即支持索引

    3. List 容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

      list.get(3)

    4. JDK API 中 List 接口的实现类有

      常用的有:ArrayList、LinkedList、Vector

  • 常用方法

    1. void add(int index,Object ele):在index位置插入ele元素

    2. boolean addAll(int index,Collection eles):从index位置开始将eles中所有元素添加进来

    3. Object get(int index):获取指定index位置的元素

    4. int indexOf(Object obj):返回obj在当前集合中首次出现的位置

    5. int lastIndexOf(Object obj):返回obj在当前集合中最后一次出现的位置

    6. Object remove(int index):移除指定index位置的元素,并返回此元素

    7. Object set(int index,Object ele):设置指定index位置的元素为ele,相当于是替换

    8. List subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置的子集合 [fromIndex,toIndex)

1、ArrayList

  • ArrayList 的底层操作机制源码分析

    1. ArrayList中维护了一个Object类型的数组elementData

      transient Object[] elementData;//transient 表示瞬间,短暂的,表示该属性不会被序列化

    2. 当创建ArrayList对象时,如果使用的时无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如果需要再次扩容,则扩容elementData为1.5倍

    3. 如果使用的是直接指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍

2、Vector底层结构和源码刨析

  • 基本介绍

    1. Vector 类定义说明

    2. Vector 底层也是一个对象数组,protected Object[] elementData;

    3. Vector 是线程同步的,即线程安全,Vector类的操作方法带有 synchronied

    4. 在开发中,需要线程同步安全时,考虑使用Vector

  • 扩容机制

    如果是无参,默认10,满后,就按2倍扩容

    如果指定大小,则每次直接按2倍扩容

3、LinkedList底层结构

  • 说明

    1. LinkedList 底层实现了双向链表和双端队列的特点

    2. 可以添加任意元素

    3. 线程不安全,没有实现同步

  • LinkedList 的底层操作机制

    1. LinkedList 底层维护了一个双向链表

    2. LinkedList 中维护了两个属性first和last分别指向首节点和尾节点

    3. 每个节点(Node对象),里面有维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表

    4. 所以LinkedList 的元素的添加删除,不是通过数组完成的,相对来说效率较高

4、ArrayList和LinkedList的比较

底层结构

增删效率

改查效率

ArrayList

可变数组

较低 数组扩容

较高

LinkedList

双向链表

较高 通过链表追加

较低

  • 如何选择

    1. 改查操作多,选择ArrayList

    2. 增删比较多,选择LinkedList

    3. 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList

    4. 在一个项目中,根据业务 灵活选择,也可能是这样,一个模块使用的是ArrayList,另一个模块是LinkedList

4、Set接口

  • Set接口基本介绍

    1. 无序(添加和取出顺序不一致),没有索引

    2. 不允许重复元素,所以最多包含一个null

    3. JDK API 中Set接口的实现类有:

  • Set接口的常用方法

    和List接口一样,Set接口也是Collection子接口,因此常用方法和Collection接口一样

  • Set接口的遍历方式

    同Collection的遍历方式一样

    不能用索引的方式来获取

1、HashSet

  1. HashSet实现了Set接口

  2. HashSet实际上是HashMap

  3. 可以存放null值,但是只能有一个null

  4. HashSet不保证元素是有序的,取决于hash后,在确定索引的结果

  5. 不能有重复的元素/对象

  • HashSet 底层机制

    HashSet 底层是(数组 + 链表 + 红黑树)

    1. HashSet 底层是 HashMap

    2. 添加存储数据表table,看这个索引位置是否已经存放元素

    3. 如果没有,则直接加入

    4. 如果有,调用equals 比较,如果相同,就放弃添加,如果不同,则添加到最后

    5. 在Java8 中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的大小 >= MIN_TREEIFY_CAPACITY(默认64)就会进行树化(红黑树)

  • 扩容机制

    1. HashSet底层是HashMap,第一次添加时,table 数组扩容到16,临界值(threshold)是16*加载因子(loadFactor)是0.75 = 12

      依照的是size(每加入一个元素,size 就会加 1)

    2. 如table 数组使用到了临界值 12,就会扩容到16*2=32,新的临界值就是32*0.75=24,以此类推

    3. 在Java8 中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的大小 >= MIN_TREEIFY_CAPACITY(默认64)就会进行树化(红黑树)

2、LinkedHashSet

  • LinkedHashSet说明

    1. LinkedHashSet是HashSet的子类

    2. LinkedHashSet 底层是一个LinkedHashMap,底层维护了一个数组 + 双向链表(LinkedHashSet 有 head 和 tail)

    3. LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的

    4. LinkedHashSet 不允许添加重复元素

    5. 每个结点有 befor 和 after 属性,这样可以形成双向链表

    6. 在添加一个元素使,先求hash值,在求索引,确定该元素在hashtable的位置,然后添加的元素加入到双向链表(如果已经存在,不添加【原则和hashset一样】)

    7. 确保遍历LinkedHashSet 插入顺序和遍历顺序一致

5、Map接口

  • Map接口实现类特点

    1. Map与Collection并列存在。用于保存具有映射关系的数据:Key - Value(双列元素)

    2. Map 中的 Key 和 value 可以是任何引用类型的数据,会封装到 HashMap$Node 对象中

    3. Map 中的 key 不允许重复(当有相同的 key ,就会替换),原因和 HashSet 一样

    4. Map 中的 value 可以重复

    5. Map 的 key 可以为 null ,value 也可以为 null,注意 key 为 null,只能有一个,value 为 null ,可以多个

    6. 常用 String 类作为 Map 的 key

    7. key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value

    8. Map存放数据的 key-value示意图,一对 k-v 是放在一个Node中的,因为 Node 实现了 Entry 接口

  • 解读

    1. k-v 最后是HashMap$Node node = newNode(hash,key,value,null)

    2. k-v 为了方便遍历,还创建 EntrySet 集合,该集合存放的元素的类型 Entry ,而一个 Entry 对象就有 k,v EntrySet<Entry<K,V>> 即: transient Set<Map.Entry<K,V>> entrySet;

    3. entrySet 中,定义的类型是 Map.Entry,但实际上存放的还是 HashMap$Node ,因为 static class Node<K,V> implements Map.Entry<K,V>

    4. 当把 HashMap$Node 对象,存放到 entrySet 就方便我们遍历,因为 Map.Entry 提供了方法 K getKey(); V getValue();

  • Map接口常用方法

    1. put:添加

    2. remove:根据键(key)删除映射关系

    3. get:根据键获取值

    4. size:获取元素个数

    5. isEmpty:判断个数是否为0

    6. clear:清除

    7. containsKey:查找键是否存在

  • Map接口遍历方法

    1. containsKey:查找键是否存在

    2. keySet:获取所有的键

    3. entrySet:获取所有关系

    4. vlaues:获取所有的值

  • HaspMap小结

    1. HashMap 使Map 接口使用频率最高的实现类

    2. HaspMap没有实现同步,因此线程是不安全的 ,方法没有做同步互斥的操作

  • HashMap底层机制及源码

    • 扩容机制

      1. HashMap 底层维护了Node 类型的数组table ,默认为null

      2. 当创建对象时将加载因子(loadfactor)初始化为0.75

      3. 当添加key-val时,通过key的哈希值得到在table的索引。然后 判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key是否和准备加入的key相等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应的处理。如果添加时发现容量不够,则需扩容

      4. 第一次添加,则需要扩容table容量为16,临界值(threshold)为12

      5. 以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,及24,以此类推

      6. 再java8 中,如果一条链表的元素个数超过 TREEIFY_THRESHOLD(默认是 8),并且 table 的大小 >= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

1、HashTable

  • HashTable 基本介绍

    1. 存放的元素是键值对:即 K - V

    2. hashTable的键和值都不能为null

    3. hashTable 使用的方法基本上和HashMap一样

    4. hashTable 是线程安全的,hashMap 是线程不安全的

  • HashTable的底层

    1. 底层有数组 HashTable$Entry[] 初始化大小为 11

    2. 临界值 threshold 8 = 11 * 0.75

    3. 按照 int newCapacity = (oldCapacity << 1) + 1; 的大小扩容

2、Properties

  • 基本介绍

    1. Properties类继承自HashTable类并实现了Map接口,也是使用一种键值对的形式来保存数据

    2. 使用特点和HashTable类似

    3. Properties 还可以用于 从 xxx.properties 问文件中,加载数据到Properties 类对象,并进行读取和修改,(xxx.properties 文件通常作为配置文件)

3、总结——开发中如何选择集合实现类

  • 先判断存储的类型(一组对象【单列】 或 一组键值对【双列】

    1. 一组对象【单列】:Collection接口

      • 允许重复:List

        • 增删改查多:LinkedList【底层 维护了一个双向链表】

        • 改查多:ArrayList【底层维护了 Object类型的可变数组】

      • 不允许重复:Set

        • 无序:HashSet【底层是HashMap,维护了一个哈希表,即(数组 + 链表 红黑树)】

        • 排序:TreeSet

        • 插入和取出顺序一致:LinkedHashSet,维护了数组 + 双向链表

    2. 一组键值对【双列】:Map

      • 键无序:HashMap【底层是:哈希表 jdk7:数组 + 链表,jdk8:数组 + 链表 + 红黑树】

      • 键排序:TreeMap

      • 键插入和取出顺序一致:LingkedHashMap

      • 读取文件:Proerties

4、Collection工具类

  • collection 工具类介绍

    1. Collection 是一个操作 Set、List 和 Map 等集合的工具类

    2. Collection 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作

  • 排序操作:(均为static方法)

    1. reverse(List):反转List中元素顺序

    2. shuffle(Lise):对List 集合元素进行随机排序

    3. sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序

    4. sort(List,Comparator):根据指定的 Comparator 产生的顺序对List 集合元素进行排序

    5. swap(List,int,int):将指定List 集合中的 i 出元素和 j 处元素进行交换

  • 查找、替换

    1. Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素

    2. Object max(Collection,Comparator):根据Comparator 指定的顺序,返回给定集合中的最大元素

    3. Object min(Collection)

    4. Object min(Collection,Comparator)

    5. int frequency(Collection,Object):返回指定集合中指定元素出现的次数

    6. void copy(List dest,List src):将src中的内容 复制到dest中

    7. boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List 对象的所有旧值