集合框架体系

Java 的集合类很多,主要分为两大类,如图 :

java 原理 实现 集合 java集合的底层原理_数组


java 原理 实现 集合 java集合的底层原理_链表_02

  1. 集合主要是两组(单列集合 , 双列集合)
  2. Collection 接口有两个重要的子接口 List 、Set , 他们的实现子类都是单列集合
  3. Map 接口的实现子类是双列集合,存放的 K-V

List接口

基本介绍

1.List的集合类中的元素是有序的,添加和取出顺序是一致的,并且元素可以重复。

2.List的集合类中的每个元素都有对应的顺序索引,即支持索引获取元素,类似数组。

ArrayList集合

  1. ArrayList可以加入null,并且多个
  2. ArrayList是由数组来实现数据存储的。底层维护了一个Object类型的数组elementData。

transient Object[] elementData;

transient表示瞬间,短暂的,表示该属性不会被序列号

  1. 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
  2. 扩容⽅式是利⽤数组的复制,因此有⼀定的开销。由于数组长度固定,扩容需要创建新的数组拷贝,按1.5倍长度扩容,效率较低。如果插入的数据不是在尾部还要移动数据。

Vector集合

  1. Vector基本等同于ArrayList,除了ArrayList是线程不安全(执行效率高).在多线程情况下,不建议使用ArrayList
  2. Vector底层也是一个对象数组,protected Object[] element Date;
  3. Vector是线程安全的,即线程同步。Vector的操作方法都有synchronized修饰。
  4. 当创建Vector对象时,如果使用无参构造器,则数组初始化容量是10,如果指定大小,则初始值为指定大小,满后按2倍扩容。

LinkedList集合

  1. LinkedList底层维护了一个双向链表,维护了两个属性first和last分别指向首节点和尾节点,实现了双向链表和双端队列特点,可以添加任意元素(元素可以重复),包括null。

java 原理 实现 集合 java集合的底层原理_链表_03

  1. 由于底层是双向链表,所以LinkedList的元素的添加和删除,相对数组来说效率较高。
  2. LinkedList没有实现同步,是线程不安全的

Set接口

基本介绍

  1. Set接口集合类是无序的,添加和取出元素顺序不一致,并且没有索引。
  2. 不允许添加重复的元素,最多只能有一个null。

HashSet集合

:可以先了解HashMap集合。

  1. hashSet的本质就是HashMap ,维护了一个数组+链表+红黑树

java 原理 实现 集合 java集合的底层原理_数组_04

底层机制

  1. 存储元素时先通过hashCode方法获取到元素的哈希值。
  2. 对哈希值进行计算,得到一个索引值,确定在数组中的位置。
  3. 如果该位置上没有元素,直接放到该位置上。如果该位置上有元素,则需要通过equals方法进行判断,如果相等,则不添加。如果不相等,则以链表的方式添加。
  4. 在java8中,如果一条链表元素个数达到8,并且数组容量达到64(默认,可以修改),就会进化成红黑树结构。

java 原理 实现 集合 java集合的底层原理_数组_05

  1. 第一次添加元素时,table数组扩容到16,并且有一个临界值=当前容量*加载因子(默认0.75),所以一开始临界值为12,当数组使用到了12时,就会进行2倍扩容,不需要到16等数组满。

LinkedHashSet集合

  1. LinkedHashSet是 HashSet的子类,不允许添加重复元素,但是元素是有序的。
  2. LinkedHashSet底层是一个 LinkedHashMap,底层维护了一个数组+双向链表(有head和tail元素)
  3. LinkedHashSet根据元素的hashCode值来决定元素的存储位置,每个节点上有before和after元素,使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

底层机制

java 原理 实现 集合 java集合的底层原理_数组_06

  1. 如图,LinkedHashSet底层维护了一个数组+双向链表,在添加元素时,先求hash值,然后求索引,确定元素在数组中的位置。
  2. 如果该位置上没有元素,直接放到该位置上。如果该位置上有元素,则需要通过equals方法进行判断,如果相等,则不添加。如果不相等,则添加到双向链表中。
  3. 这样我们在遍历LinkedHashSet时,可以确保插入顺序和取出顺序是一致的。

Map接口

:这里讲的是JDK8的Map接口特点

  1. Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value。
  2. Map 中的key和 value可以是任何引用类型的数据,会封装到HashMap$Node对象中。
  3. Map中的key不允许重复,原因和HashSet一样,Map中的value可以重复。
  4. Map的key可以为null, value也可以为null,注意key为null, 只能有一个,value为null ,可以多个。
  5. key和 value之间存在单向一对一关系,即通过指定的key 总能找到对应的value。

HashMap集合

  1. Map存放数据的key-value示意图,一对k-v是放在一个HashMap$Node中的。

java 原理 实现 集合 java集合的底层原理_java 原理 实现 集合_07

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

底层机制

  1. 存储元素时先通过hashCode方法获取到元素的哈希值。
  2. 对哈希值进行计算,得到一个索引值,确定在数组中的位置。
  3. 如果该位置上没有元素,直接放到该位置上。如果该位置上有元素,则需要通过equals方法进行判断,如果相等,则不添加。如果不相等,则以链表的方式添加。
  4. 在java8中,如果一条链表元素个数达到8,并且数组容量达到64(默认,可以修改),就会进化成红黑树结构。
  5. 第一次添加元素时,table数组扩容到16,并且有一个临界值=当前容量*加载因子(默认0.75),所以一开始临界值为12,当数组使用到了12时,就会进行2倍扩容,不需要到16等数组满。

:可以配合HashSet中的图进行理解。

Hashtable

  1. 存放的元素是键值对:即K-V
  2. hashtable的键和值都不能为null,否则会抛出NullPointerException
  3. hashTable使用方法基本上和HashMap一样
  4. hashTable是线程安全的(synchronized),所以效率较低

Collections 工具类

Collections 工具类介绍

  1. Collections是一个操作 Set、List和Map等集合的工具类
  2. Collections中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作

排序操作

均为 static 方法

  1. reverse(List): 反转 List中元素的顺序
  2. shuffle(List): 对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);根据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 对象的所有旧值