List的徒子徒孙们

安稳与你 提交于 2020-03-22 23:44:39

3 月,跳不动了?>>>

1. 徒子徒孙报道

        从 Collection家族成员 中可以知道List的徒子徒孙们有(绿色为实现,橙色为继承):

AbstractList :     SubList :    RandomAccessSubList

                            AbstractSequentialList:    LinkedList

                            ArrayList

                            Vector : Stack

ArrayList

LinkedList

Vector:    Stack

问题:从这些关系里很明显发现AbstractList已经实现了List接口,而ArrayList和Vector是继承它的,为什么ArrayList和Vector还实现List接口?

2. AbstractCollection、AbstractList两个抽象类的功能

AbstractCollection:实现了移除指定元素返回boolean值的功能(依靠迭代器实现的,但此类并未实现迭代器的功能);判断集合包含元素功能;转化成数组的功能。

AbstractList:只实现了迭代器功能,继承AbstractCollection实现的功能。

总结:(1) 这两个抽象类都未实现元素的添加操作,但却定义了各种用到add的方法,算是搭了骨架,只要后面的徒子徒孙们实现add操作,remove操作即可融汇贯通。

(2) 集合的接口和抽象类都未见存储元素的容器(说明这个容器的结构是不确定的),而是放在具体子类去实现。所以,接口和抽象类都无法去直接做元素的添加和移除功能(因为没有容器)。至于上面所说的移除指定元素返回boolean值得功能则是依靠迭代器的方法实现。

(3) 回到1里面提到的问题:a.抽象类是很低级的,它可以”纸上谈兵“,抽象类就抽了同类的共性,在这里,所有的继承AbstractCollection的集合类,都会涉及到移除指定元素的操作,为了能重复利用通过迭代器去移除元素的代码,所以在顶级抽象类AbstractCollection中实现了,那么它的子类将无需在现实,这是通用功能。b. 至于子类为什么还去实现父类的实现的接口,我表示完全可以不去实现,唯一的好处就是一目了然,知道子类实现了某接口,而不要进入父类里面查看。若是有人发现还有深层妙处,请告知,感激不尽!

3. ArrayList细节

(1) ArrayList的元素容器是数组,通过new ArrayList()创建对象时,数组为空,当有第一个元素添加时,马上对数组进行扩容,数组长度变成10。建议:若是事先知道集合元素个数,最好的方法是直接使用对象数组或者new ArrayList(count)。若明确知道集合不为空,又不知元素个数,则new ArrayList(10)。当然ArrayList有个收缩的方法:trimToSize(),该方法就是去除数组未使用的位置(类似于字符串去除结尾的空字符String::trim())。

(2) ArrayList的扩容机制: 第一次添加元素时,上面说了,就是扩容到10。之后的扩容是,当前数组大小加上当前数组大小的一半。扩容是要付出代价的,会新建一个数组,将原数组的元素的复制到新数组中。

(3) ArrayList的内存释放: clear()方法,里面遍历数组,将元素置null。

(4) ArrayList实现了序列化接口,但是定义的数组对象是transient,说明它不在序列化之内。

4. Vector 和 Stack细节

(1) Vector的元素容器也是数组, 通过new Vector()创建对象,数组默认大小为10。它可以自定义定义数组的初始大小和扩容大小。

(2) Vector的数组对象是可被序列化的。

(3) Vector的添加、获取、移除元素的方法都加了synchronized。说明Vector操作都是线程安全的,同样这也是耗性能的对象。

(4) Stack 栈对象,后进先出,初始化时,数组为空。

5. LinkedList细节

(1) LinkedList的元素容器的结构:一个链表。下面是链表的节点类的源码。

private static class Node<E> {
  E item;               // 数据
  Node<E> next;         // 下一个节点
  Node<E> prev;         // 上一个节点

  Node(Node<E> prev, E element, Node<E> next) {
     this.item = element;
     this.next = next;
     this.prev = prev;
  }
}

链表结构能够快速的任意位置的插入元素,删除元素,但是链表的元素遍历速度没有数组快(存储结构差异决定,数组是连续的内存,链表是分散的内存,要找到某个元素,那么链表肯定比数组复杂,数组只需寄存器++,而链表需要寄存器重新赋值)。

(2) LinkedList虽然实现了序列化接口,但是它里面的成员都不在序列化范围内。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!