浅谈Java集合类(一)【List】

前不久,面试的时候被主考官问道集合,一直以来都以为概念应该不会出错的,但是,竟然令人发指的打错了,哎,久久不能平复呀

好了,废话不多说,开始正文吧。

java集合为我们定义了大量的接口和抽象类,他们都支持泛型编程,所以使用起来很方便。首先集合有两个基本的接口:Collection和Map。List,Set,Queue...的就实现了Collection。像什么SortMap,HashMap...就实现了Map.

废话不多说,直接上图。

:

好了,我们先从Collection中的List来说起:

List相当于一类相同类型的集合,他能够按照原先插入的顺序输出,也称为是有序同时允许含有重复元素的集合,主要实现类有ArrayList,LinkedList,Vector...

他的主要接口有如下:

<span style="font-size:14px;"><span style="font-size:12px;">ListIterator<E> listIterator();
//返回一个列表迭代器,以便访问列表的元素
ListIterator<E> listIterator(int index);
//返回一个列表迭代器,用来访问列表中的元素,这个元素第一次调用next返回给定索引的特定值
void add(int i, E element);
//在给定索引位置插入元素
void addAll(int i, Collection<? extend E>elements);
//将集合插入某个指定位置
E remove(int i);
//删除给定位置的元素并放回
E get(i);
//放回给定位置的元素
E set(int i, E element);
//将给定位置的元素设置为element,并返回之前的元素
int indexOf(Object element);
//返回指定元素第一次出现的位置,假如没有这个元素将返回-1
int lastIndexOf(Object element);
//返回指定元素最后一次出现的位置,假如没有该元素返回-1</span></span>
好了,我觉得需要记住的是,接口给了我们随机访问的接口和插入的接口。当然在存在ide的时候我们可以看提示,但是,笔试或者面试可没有,所以可以好好注意一下。

到这,我觉得我有必要说说他的实现类了。

先来道道ArrayList吧。首先,它和我们学C语言时接触的数组非常的相似。不同的是它是一种动态数组,在元素达到存满之后会自动扩容,扩容大小为原来的1.5倍。当数据插入完毕后,我们也可以将数组多余的空间返回给jvm。当然说到这,我们必须注意一个事实,每次扩容,都需要把空间的元素全部复制到新空间中,这无疑增加了系统的开销,影响了性能。所以在初始化是我们可以传入ArrayList(int initialCapacity)的具体值,以优化我们的程序。因为它是动态数组,所以,我们能够很清楚的知道,它的一个优点,随机访问性能非常优异,因为能直接根据索引取值,所以随机访问的时间复杂度为o(1)。所以,在进行遍历时,并不需要把它转化为Iterator,而是直接根据它的索引进行遍历。但是,我们也很清楚的知道它的一个确定。在进行随机插入时,性能就让我们汗颜了。因为每一次的随机插入后者删除,都必须把它之后的元素进行前移或后移。当数据规模不大时,可能还能接受,但是数据规模几百万数据,几千万呢,哎想想都可怕...

    好了,到LinkedList了。他呢,相当于我们数据结构学的链表,它也的确是链表实现的。好了,到这,我们回想一下,链表的优缺点。

优点:1.随机的插入删除很方便,效率高.

     2.数据大小不确定时,并且插入删除频繁时,我们选用它很合适

缺点:1.随机访问效率很低,需要从头开始遍历或者记住尾节点也可以从尾部向前开始遍历

     2.因为需要记住下一结点的地址,所以和数组相比记录相同的数量的数据,所占用的空间肯定是多一点.

需要特别提醒的是,记得之前我们说过,List接口定义了随机遍历的方法即:E get(int index);但是呢,我们在调用LinkedList中的get(index)方法时,的确会返回正确的值,但是呢它是o(n)级别的访问,因为链表不支持索引的自身并不通过索引的方式访问值,所以我们每次调值的时候它都会从第一个元素开始访问。因此,有一个问题我们得好好考虑了。具体看下面代码。

<span style="font-size:14px;">List<Object> list = new LinkedList()<>;
....
for (int i = 0; i < list.size(); i++){</span>
<span style="font-size:14px;">     get(i);
}</span>
    我们想一下,这个的遍历一次的时间复杂度是多少呢?没错,相信聪明的你已经想到o(n^2);很明显,这效率不高,那我们有什么办法访问呢。

    没错,那就是调用迭代器。所以在我们对链表进行遍历的时候,就调用itorater(),或者listItorater();

LinkedList继承了他们所有的优缺点,所以什么时候用ArrayList,什么时候用LinkedList呢。一般来说当频繁的随机读取,而且插入删除操作比较少的话,毫无疑问的使用ArrayList,有一个可以考虑的是,初始化时,我们为它赋予初始化大小,能够做到一定程度的优化。当有大量的插入删除,很少又随机访问时,我们选用LinkedList最为合适。

接下来,我们来了解一个叫做Vector的List的实现类。它和ArrayList和LinkedList不是一个时代的产物,它从JDK1.0就开始发布,他的数据结构基本和ArrayList相同(这只能说是我从各种资料上总结出来的,因为没看源码,所以本着谨慎的态度在这给个提醒),但是它和ArrayList相比除了历史又有什么不同呢。

首先我得说下,他的效率并不如ArrayList,为什么呢。我想它实现了同步方法是一个很重要的原因。在有多线程的时候,我们调用它能够使我们的代码更加简洁,更加简单。

到这呢,List的大部分的内容已经讲完了。但是还是有缺陷,现在很明显随着多核处理器的普及,单单靠他们实现多线程并发编程的话,有时候很比较复杂,需要考虑同步的地方很多,显得有点繁琐,那么我们该怎么做呢。下面我还会继续介绍,请客官稍安勿躁。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值