ArrayList:
https://blog.csdn.net/weixin_36378917/article/details/81812210
特点:list接口的主要实现类,线程是不安全的,效率高
数据结构:ArrayList的底层数据结构就是一个数组,数组元素的类型为Object类型,对ArrayList的所有操作底层都是基于数组的。
线程安全性:对ArrayList进行添加元素的操作的时候是分两个步骤进行的,即第一步先在object[size]的位置上存放需要添加的元素;第二步将size的值增加1。由于这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境下是线程不安全的。
如果非要在多线程的环境下使用ArrayList,就需要保证它的线程安全性,通常有两种解决办法:第一,使用synchronized关键字;第二,可以用Collections类中的静态方法synchronizedList();对ArrayList进行调用即可。
源码分析:jdk7情况下
ArrayList list = new ArrayList();//创建了长度为10的Object[]数组elementData list.add(123); ... list.add(456);//如果此次的添加导致底层elementData数组容量不够,则扩容。默认情况下,扩容为原来容量的1.5倍,同时需要将原来数组中的数据复制到新的数组中去。源码分析:jdk8情况下
ArrayList list = new ArrayList();//底层Object[] elementData初始化为{},没有创建长度为10的数组 list.add(123);//第一次调用add()时,底层才创建了长度为10的数组,并将数据123添加到elementData[]数组中 //后续的添加和扩容操作与jdk7一样elementData存储:
Linkedlist:对于频繁的插入删除操作,使用此类效率比Arraylist高,底层使用双向链表存储。
Vector:作为list接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储
一、Set:存储无序的,不可重复的数据
以HashSet为例说明:
1.无序性:不等于随机性。存储的数据在底层数组中并非按照数组索引的顺序添加,而是根据数据的哈希值决定。
2.不可重复性: 保证添加的元素按照equal()判断时,不能返回true。即:相同的元素只能添加一个。
二、添加元素的过程:以HashSete为例
我们向HashSet中添加元素a,首先调用元素a所在类的hashcode()方法,计算a的哈希值,此哈希值接着通过某种方法计算出在HashSet底层数组中的存放位置(即为索引位置),判断数组此位置上是否已经有元素:
(1)如果此位置上没有其它元素,则元素a添加成功。 --->情况1
(2)如果此位置上有其它元素b(或以链表形式存在的多个元素),则比较元素a和元素b的hash值:
如果哈希值不同,则元素a添加成功。--->情况2
如果哈希值相同,进而需要调用元素a所在类的equal()方法,equal()返回true,元素a添加失败,返回false,则元素添加成功。--->情况3
对于添加成功的情况2和情况3而言:元素a与已经存放在指定索引位置上数据以链表的方式存储。
jdk7:元素a放到数组中,指向原来的元素
jdk8:原来的元素在数组中,指向元素a
Set接口中没有额外定义新的方法,使用的都是Collection中声明过的方法。
LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历,对于频繁的遍历操作,LinkedHashSet效率高于HashSet.
TreeSet
添加数据的时候,必须是相同类的对象 ;
1.自然排序中,比较两个对象是否相同的标准为:compareTo()返回0.不再是equals().
2.定制排序中,比较两个对象是否相同的标准为:compare()返回0.不再是equal()