JDK之List分析
List在平时的开发当中用的也很多,但是一般都是面向接口编程,所以使用的是List类型,但是都是用ArrayList或者LinkedList进行相关操作。本文章主要讲解JDK源码之ArrayList和LinkedList。
ArrayList底层采用的是数组的形式维护的,主要的方法有add,remove,size,contains,toArray等相关方法。add其实很简单,底层就是增加数组的长度,然后将要加入的元素放进数组。其实现方式方法为:this.elementData[(this.size++)] = paramE,在此操作之前,会增加将数组的长度加1,以放入新加的元素进入到当前数组中,也就实现了List的增加功能。但是,如果要想插入到指定的位置,操作就复杂一些。它会将当前数组向后移动1位,使用的是System.arraycopy复制后面的元素,然后将指定的元素插入。这样的时间就是代价。所以在插入元素比较多的情况下,优先使用Linkedlist,待会会做介绍。remove道理是一样的。不过remove有重载。当为下标int时,它会将指定的元素复制,然后将指定下标的元素设置为null,这样就实现了指定下标删除的功能。但是重载的不一样。他接收Object类型,这样,不管list中存储的是什么类型,都可以进行remove。使用这个方法时,它会搜索符合条件的元素,并取到下标,然后使用firstRemove方法移除指定的元素。当然这种方法只能移除第一个元素,如果想要移除匹配的所有元素,就得遍历,或者使用removeAll方法了。需要注意的是,removeAll接收参数为Collection的。至于ArrayList中的size就很简单了,因为底层是数组,所以只需要返回当前数组的大小就是此list长度了。contains返回的是当前数组的下标,使用方法indexOf,如果没有则indexOf回返-1。toArray方法返回的是list数组的形式,直接使用Array中的copy即可。其实ArrayList中有个重要的方法,就是迭代器,不过迭代器是在父类AbstractList中的,且放在了内部类Itr中,使用时,直接定义一个迭代器Iterator,然后调用iterator方法,此方法返回内部类的对象,此时就可以通过这个对象进行迭代,包括方法next和hasNext。这个是最常用的,此处重点分析实现。我们可以先定义一个接口类型的Iterator,使用iterator()直接获取对象,此方法返回的是一个Itr对象(内部类,存在于父类中),这个内部类包含了next和hasNext,然后就可以使用这个对象去遍历数组。hasNext即判断当前是否还有元素,这个方法使用了游标的概念,当前游标与当前数组的大小是否相等,返回true或false。然后使用hasNext拿出值,并将游标向后移动一位。这样就可以遍历数组了。当然这个方法是在父类中,在ArrayList中时看不见的。迭代器使用了典型的面向接口编程思想,只是定义了接口类型,然后去调用实现类中相关的方法。(面向接口编程后期会做具体分析)。API中说使用了迭代器以后,就不能对该list进行更改了,具体原因我在JDK中没有找出。初步分析是由于游标的缘故,希望知道的网友给出答案。(ArrayList不是线程安全的,API中讲到,如果他线程安全,只需将其放到Collections.synchronizedList中,这个在工作中还真的很少用到,看了JDK的源码,其做法是将list放进SynchronizedList代码块中,具体的实现不看了,反正我很少用到。
LinkedList跟ArrayList很多方法的功能都是一样的,但是实现方式方法却很不一样。他的底层使用的是链表实现的,使用了内部类Entry,Entry包含了element、next、previous。当实例化list的时候,就会对这三个变量进行赋值,后期的一切操作都是围绕着这三个变量展开。在这同样先分析方法add,remove,size,contains方法。在介绍add之前先介绍addBefore。addBefore是将当前元素封装成一个Entry,然后next和previous分别重新赋值,这样就实现了链表的向后移动,即望链表上加入元素。链表这个东西有兴趣的可以自己看看数据结构。add方法调用的就是addBefore,但是对于链表中的next使用的是header,这样就将元素加入到了链表。此list的add方法代价是巨大的,因为他要移动链表的next和previous,没有ArrayList中简单,直接赋值就可以了。remove方法的实现原理差不多,也是对链表进行的操作。size方法就是返回当前链表的长度,不做过多介绍。contains方法就是对链表进行的遍历,一步一步移动链表,并进行匹配。toArray方法底层的实现是将链表的元素取出来,放进一个数组,并返回该数组,而病史想ArrayList中那样,直接返回数组。LinkedList的迭代器与ArrayList的迭代器相似,但是底层的实现不一样,如hasNext,他是用的是this.nextIndex来判断是否有下一个元素,而并不是查看数组中是否有元素。关于LinkedList需要深入的看下,今天我只看了一些表面的知识,以后会补充上来。
今晚就分析到这,其实这两个类中还有很多地方需要看,希望广大网友提供很好的分析,相互学习。