0
点赞
收藏
分享

微信扫一扫

聊聊集合


日前,网络流传“治疗罕见病‘脊髓性肌萎缩症’特效药物需‘70万元一支’天价,且国内价格远高于国外”,引发社会关注。


让我突然想到了“我不是药神”,一个抗癌药物让外国人赚到了暴利,国内那些所谓的黄牛也从中牟利,这也就让很多外国人说中国人没有信仰。的确,从马斯洛的需求理论来说,的确大部人还在下层。

聊聊集合_线程安全


谈谈技术吧

 ArrayList和 Vector 的区别。

这两个类都实现了 List 接口(List 接口继承了Collection 接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素,并且其中的数据是允许重复的,这是 HashSet 之类的集合的最大不同处,HashSet 之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素(本来题目问的与 hashset 没有任何关系,但为了说清楚 ArrayList 与 Vector 的功能,我们使用对比方式,更有利于说明问题)。接着才说ArrayList 与 Vector 的区别,这主要包括两个方面。

  • 同步性:

Vector 是线程安全的,也就是说是它的方法之间是线程同步的,而 ArrayList 是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用 ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用 Vector,因为不需要我们自己再去考虑和编写线程安全的代码。

备注:对于 Vector&ArrayList、Hashtable&HashMap,要记住线程安全的问题,记住 Vector 与 Hashtable 是旧的,是 java 一诞生就提供了的,它们是线程安全的,ArrayList 与 HashMap 是 java2 时才提供的,它们是线程不安全的。所以,我们讲课时先讲老的。

  • 数据增长:

ArrayList 与Vector 都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加 ArrayList与 Vector 的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector 默认增长为原来两倍,而 ArrayList 的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的 1.5 倍)。ArrayList 与Vector 都可以设置初始的空间大小,Vector 还可以设置增长的空间大小,而 ArrayList 没有提供设置增长空间的方法。

总结:即 Vector 增长原来的一倍,ArrayList 增加原来的 0.5 倍。


ArrayList

ArrayList底层是由动态数组实现的。动态数组就是长度不固定,随着数据的增多而变长。当实例化ArrayList时(比如:List<Integer> intList = new ArrayList<>();),如果不指定它的长度,则默认为10,如下图:

聊聊集合_线程安全_02

当ArrayList增加元素时,它是按照顺序从头部开始往后添加,它是有顺序的。如下图

聊聊集合_线程安全_03

如果当添加的元素超过当前数组的长度时,它会新创建一个数组,长度为当前数组的1.5倍,然后将当前数组的元素复制到新的数组,当前数组的内存被释放。如下图

聊聊集合_线程安全_04

根据上图我们可以发现新的数组由原来的长度10变为现在的15.

    我们知道,数组是用来存储固定大小的同类型元素,数组存放位置是在jvm的堆中。当有新的元素需要存储时,都会存储在最前面,因此每次存储,所有的元素都会向后移动位置。同理,如果删除一个元素,后面的元素都会向前移动一个位置。因此,ArrayList在存储和删除的时候效率比较低。

    但是由于每个元素占用的内存相同且是连续排列的,因此在查找的时候,根据元素的下标可以迅速访问数组中的任意元素,查询效率非常高。

LinkedList

LinkedList底层是由双向链表的数据结构实现的。

聊聊集合_线程安全_05

由上图可以看到:双向链表是由三个部分组成:prev、data、next.

prev:由用来存储上一个节点的地址;

data:是用来存储要存储的数据;

next:是用来存储下一个节点的地址。

聊聊集合_数组_06

上图可以看出双向链表每个元素之间的联系。我故意将每个链表画的分布不均匀是因为它不像数组一样是连续排列的,双向链表是可以占用一段不连续的内存空间。

当我们有新元素插入时,只需要修改所要插入位置的前一个元素的next值和后一个元素的prev值即可。比如我们在数据2与数据6之间插入一个数据4的元素,那么只需要修改数据2的next值和数据6的prev值。如下图

聊聊集合_线程安全_07

删除也是同理,比如要删除数据8的元素,只需要修改数据7的next值和数据9的prev值即可,然后数据8没有元素指向它,它就成了垃圾对象,最后被回收。因此在增加和删除的时候只需要更改前后元素的next和prev值,效率非常高。但是在查询的时候需要从第一个元素开始查找,直到找到我们需要的数据为止,因此查询的效率比较低。



举报

相关推荐

0 条评论