Java集合框架
1、集合分类
这是我自己简化的关于Java集合框架的关系图
根据图可以看出来,集合框架总共有两个大类Collection和Map,这是两个根接口,他们下面有一些实现类。
每个类别下用常用的实现类颜色是加深的。
2、Collection理解
Collection接口定义的是一个单列的集合,也定义了很多对集合进行操作的方法。它有两个主要的子接口List和Set。
1. List
List:存储的数据时有序、可重复。可以通过索引来访问数据。索引相当于数组的下标,从0开始。
List下面有两个主要的实现类:ArrayList、LinkedList。
(1)ArrayList
特点:有序、可重复、有索引、可为null、查询块、增删慢、线程不安全
底层实现:数组
实现原理:使用JDK7和JDK8进行比较。
JDK7:当你ArrayList list = new ArrayList();时,系统会初始化一个大小为10的Object[]数组,每次进行list.add(数据);操作时,都会判断当前数组容量是否足够,如果容量不够就会进行扩容,扩容为原来的1.5倍。扩容其实就是新建一个原来大小1.5倍的数组,然后将原来的数据复制到新数组当中。
JDK8:当你ArrayList list = new ArrayList();是,系统并不会给你创建一个容量为10的Object[]数组,而是给你一个空的常量数组。在第一次进行list.add(数据);操作时,才会给你创建一个容量为10的数组,扩容机制和JDK7是一样的。
JDK7就像是单例模式中的饿汉式(直接创建好),而JDK8就像是懒汉式(你问我要我才给你创建)。
(2)LinkedList
特点:有序、可重复、可为null、查询慢、增删块、线程不安全
底层实现:双向链表
(3)Vector
这个也是List下的实现类,但是现在已经不怎么用了,它的特点就是线程安全。
Set
Set:存储的数据无序、不可重复,和高中学的集合很像。可以有null值,但是只能有一个。存储的必须是对象。不能是基本数据类型,如果是基本数据类型就要用包装类。
在这里需要理解一下什么叫做无序和不可重复。
无序:并不是说因为输出的顺序不一样就叫做无序,这里的无序指的是保存的值在内存中的地址是随机的。
不可重复:这里的不可重复不仅仅指数据不重复,而是通过对象的hashCode()和equals()两个方法来判断是否重复。
Set就是一个特殊的Map
Set中的方法全部都是继承Collection接口的。
Set主要有三个实现类:HashSet、LinkedHashSet、TreeSet,
(1) HashSet
特点:无序、不可重复、只能有一个null值、线程不安全的
底层实现:哈希表
(2) LinkedHashSet
特点:继承于HashSet,增加了链表结构,可以根据数据的插入顺序输出,存储的数据不可重复。链表就是用来记录数据的顺序。
底层实现:哈希表+链表
(3) TreeSet
特点:可以根据存储的对象的属性值进行特定的排序。数据不可重复。
底层实现:红黑树(还不太了解,等了解了再来补充)
注意:TreeSet不是通过hashCode()和equals()来判断重复的,而是使用Comparable或Comparator来判断的。
3、Map理解
Map是一个双列集合,以key-value的方式来保存数据,key相当于一个set,value相当于一个Collection。存储的数据需要重写hashCode()、equals()方法。
HashMap
特点:双列集合,key不可重复,可以是null,但是只能有一个null,value可以重复,一个key对应一个value
底层实现:
JDK7:哈希表+链表
JDK8:哈希表+链表/红黑树
HashMap初始化大小为16,加载因子为0.75,每当HashMap的大小达到了size * 0.75 就会发生扩容,每次扩容为原来的2倍。因为底层使用的位运算,每次扩容的时候数组大小直接左移一位,相当于乘2.当链表长度大于8并且数组大小大于64就会把链表用红黑树来代替。如果链表长度达到了8但是数组大小不够64就会进行扩容。在JDK7的时候链表采用头插法,在并发条件下回形成链表环。在JDK8的时候采用尾插法。JDK7的时候是你在new的时候就把数组创建了,而JDK8的时候是在进行第一次add的时候才给你创建一个默认大小的数组。
LinkedHashMap
特点:继承于HashMap,可以保留数据的输入顺序。
底层实现:哈希表+链表
TreeMap
特点:可以根据存储的数据的属性值进行排序。
Hashtable
特点:线程安全,不可存null值。
Properties
通常用来处理配置文件的数据。
写在最后