Java集合源码剖析(一)【集合框架概述,Jetpack-MVVM-高频提问和解答

  1. elementData[–size] = null; // Let gc do its work

  2. return oldValue;

  3. }

  4. // 删除ArrayList的指定元素

  5. public boolean remove(Object o) {

  6. if (o == null) {

  7. for (int index = 0; index < size; index++)

  8. if (elementData[index] == null) {

  9. fastRemove(index);

  10. return true;

  11. }

  12. } else {

  13. for (int index = 0; index < size; index++)

  14. if (o.equals(elementData[index])) {

  15. fastRemove(index);

  16. return true;

  17. }

  18. }

  19. return false;

  20. }

  21. // 快速删除第index个元素

  22. private void fastRemove(int index) {

  23. modCount++;

  24. int numMoved = size - index - 1;

  25. // 从"index+1"开始,用后面的元素替换前面的元素。

  26. if (numMoved > 0)

  27. System.arraycopy(elementData, index+1, elementData, index,

  28. numMoved);

  29. // 将最后一个元素设为null

  30. elementData[–size] = null; // Let gc do its work

  31. }

  32. // 删除元素

  33. public boolean remove(Object o) {

  34. if (o == null) {

  35. for (int index = 0; index < size; index++)

  36. if (elementData[index] == null) {

  37. fastRemove(index);

  38. return true;

  39. }

  40. } else {

  41. // 便利ArrayList,找到“元素o”,则删除,并返回true。

  42. for (int index = 0; index < size; index++)

  43. if (o.equals(elementData[index])) {

  44. fastRemove(index);

  45. return true;

  46. }

  47. }

  48. return false;

  49. }

  50. // 清空ArrayList,将全部的元素设为null

  51. public void clear() {

  52. modCount++;

  53. for (int i = 0; i < size; i++)

  54. elementData[i] = null;

  55. size = 0;

  56. }

  57. // 将集合c追加到ArrayList中

  58. public boolean addAll(Collection<? extends E> c) {

  59. Object[] a = c.toArray();

  60. int numNew = a.length;

  61. ensureCapacity(size + numNew);  // Increments modCount

  62. System.arraycopy(a, 0, elementData, size, numNew);

  63. size += numNew;

  64. return numNew != 0;

  65. }

  66. // 从index位置开始,将集合c添加到ArrayList

  67. public boolean addAll(int index, Collection<? extends E> c) {

  68. if (index > size || index < 0)

  69. throw new IndexOutOfBoundsException(

  70. "Index: " + index + ", Size: " + size);

  71. Object[] a = c.toArray();

  72. int numNew = a.length;

  73. ensureCapacity(size + numNew);  // Increments modCount

  74. int numMoved = size - index;

  75. if (numMoved > 0)

  76. System.arraycopy(elementData, index, elementData, index + numNew,

  77. numMoved);

  78. System.arraycopy(a, 0, elementData, index, numNew);

  79. size += numNew;

  80. return numNew != 0;

  81. }

  82. // 删除fromIndex到toIndex之间的全部元素。

  83. protected void removeRange(int fromIndex, int toIndex) {

  84. modCount++;

  85. int numMoved = size - toIndex;

  86. System.arraycopy(elementData, toIndex, elementData, fromIndex,

  87. numMoved);

  88. // Let gc do its work

  89. int newSize = size - (toIndex-fromIndex);

  90. while (size != newSize)

  91. elementData[–size] = null;

  92. }

  93. private void RangeCheck(int index) {

  94. if (index >= size)

  95. throw new IndexOutOfBoundsException(

  96. "Index: “+index+”, Size: "+size);

  97. }

  98. // 克隆函数

  99. public Object clone() {

  100. try {

  101. ArrayList v = (ArrayList) super.clone();

  102. // 将当前ArrayList的全部元素拷贝到v中

  103. v.elementData = Arrays.copyOf(elementData, size);

  104. v.modCount = 0;

  105. return v;

  106. } catch (CloneNotSupportedException e) {

  107. // this shouldn’t happen, since we are Cloneable

  108. throw new InternalError();

  109. }

  110. }

  111. // java.io.Serializable的写入函数

  112. // 将ArrayList的“容量,所有的元素值”都写入到输出流中

  113. private void writeObject(java.io.ObjectOutputStream s)

  114. throws java.io.IOException{

  115. // Write out element count, and any hidden stuff

  116. int expectedModCount = modCount;

  117. s.defaultWriteObject();

  118. // 写入“数组的容量”

  119. s.writeInt(elementData.length);

  120. // 写入“数组的每一个元素”

  121. for (int i=0; i<size; i++)

  122. s.writeObject(elementData[i]);

  123. if (modCount != expectedModCount) {

  124. throw new ConcurrentModificationException();

  125. }

  126. }

  127. // java.io.Serializable的读取函数:根据写入方式读出

  128. // 先将ArrayList的“容量”读出,然后将“所有的元素值”读出

  129. private void readObject(java.io.ObjectInputStream s)

  130. throws java.io.IOException, ClassNotFoundException {

  131. // Read in size, and any hidden stuff

  132. s.defaultReadObject();

  133. // 从输入流中读取ArrayList的“容量”

  134. int arrayLength = s.readInt();

  135. Object[] a = elementData = new Object[arrayLength];

  136. // 从输入流中将“所有的元素值”读出

  137. for (int i=0; i<size; i++)

  138. a[i] = s.readObject();

  139. }

  140. }

几点总结

关于ArrayList的源码,给出几点比较重要的总结:

1、注意其三个不同的构造方法。无参构造方法构造的ArrayList的容量默认为10,带有Collection参数的构造方法,将Collection转化为数组赋给ArrayList的实现数组elementData。

2、注意扩充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。当容量不足以容纳当前的元素个数时,就设置新的容量为旧的容量的1.5倍加1,如果设置后的新容量还不够,则直接新容量设置为传入的参数(也就是所需的容量),而后用Arrays.copyof()方法将元素拷贝到新的数组(详见下面的第3点)。从中可以看出,当容量不够时,每次增加元素,都要将原来的元素拷贝到一个新的数组中,非常之耗时,也因此建议在事先能确定元素数量的情况下,才使用ArrayList,否则建议使用LinkedList。

3、ArrayList的实现中大量地调用了Arrays.copyof()和System.arraycopy()方法。我们有必要对这两个方法的实现做下深入的了解。

首先来看Arrays.copyof()方法。它有很多个重载的方法,但实现思路都是一样的,我们来看泛型版本的源码:

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public static  T[] copyOf(T[] original, int newLength) {

  2. return (T[]) copyOf(original, newLength, original.getClass());

  3. }

很明显调用了另一个copyof方法,该方法有三个参数,最后一个参数指明要转换的数据的类型,其源码如下:

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {

  2. T[] copy = ((Object)newType == (Object)Object[].class)

  3. ? (T[]) new Object[newLength]

  4. : (T[]) Array.newInstance(newType.getComponentType(), newLength);

  5. System.arraycopy(original, 0, copy, 0,

  6. Math.min(original.length, newLength));

  7. return copy;

  8. }

这里可以很明显地看出,该方法实际上是在其内部又创建了一个长度为newlength的数组,调用System.arraycopy()方法,将原来数组中的元素复制到了新的数组中。

下面来看System.arraycopy()方法。该方法被标记了native,调用了系统的C/C++代码,在JDK中是看不到的,但在openJDK中可以看到其源码。该函数实际上最终调用了C语言的memmove()函数,因此它可以保证同一个数组内元素的正确复制和移动,比一般的复制方法的实现效率要高很多,很适合用来批量处理数组。Java强烈推荐在复制大量数组元素时用该方法,以取得更高的效率。

4、注意ArrayList的两个转化为静态数组的toArray方法。

第一个,Object[] toArray()方法。该方法有可能会抛出java.lang.ClassCastException异常,如果直接用向下转型的方法,将整个ArrayList集合转变为指定类型的Array数组,便会抛出该异常,而如果转化为Array数组时不向下转型,而是将每个元素向下转型,则不会抛出该异常,显然对数组中的元素一个个进行向下转型,效率不高,且不太方便。

第二个, T[] toArray(T[] a)方法。该方法可以直接将ArrayList转换得到的Array进行整体向下转型(转型其实是在该方法的源码中实现的),且从该方法的源码中可以看出,参数a的大小不足时,内部会调用Arrays.copyOf方法,该方法内部创建一个新的数组返回,因此对该方法的常用形式如下:

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. public static Integer[] vectorToArray2(ArrayList v) {

  2. Integer[] newText = (Integer[])v.toArray(new Integer[0]);

  3. return newText;

  4. }

5、ArrayList基于数组实现,可以通过下标索引直接查找到指定位置的元素,因此查找效率高,但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低。

6、在查找给定元素索引值等的方法中,源码都将该元素的值分为null和不为null两种情况处理,ArrayList中允许元素为null。

LinkedList源码剖析

LinkedList简介

LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈、队列和双端队列来使用。

LinkedList同样是非线程安全的,只在单线程下适合使用。

LinkedList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆。

LinkedList源码剖析

======================

LinkedList的源码如下(加入了比较详细的注释):

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. package java.util;

  2. public class LinkedList

  3. extends AbstractSequentialList

  4. implements List, Deque, Cloneable, java.io.Serializable

  5. {

  6. // 链表的表头,表头不包含任何数据。Entry是个链表类数据结构。

  7. private transient Entry header = new Entry(null, null, null);

  8. // LinkedList中元素个数

  9. private transient int size = 0;

  10. // 默认构造函数:创建一个空的链表

  11. public LinkedList() {

  12. header.next = header.previous = header;

  13. }

  14. // 包含“集合”的构造函数:创建一个包含“集合”的LinkedList

  15. public LinkedList(Collection<? extends E> c) {

  16. this();

  17. addAll©;

  18. }

  19. // 获取LinkedList的第一个元素

  20. public E getFirst() {

  21. if (size==0)

  22. throw new NoSuchElementException();

  23. // 链表的表头header中不包含数据。

  24. // 这里返回header所指下一个节点所包含的数据。

  25. return header.next.element;

  26. }

  27. // 获取LinkedList的最后一个元素

  28. public E getLast()  {

  29. if (size==0)

  30. throw new NoSuchElementException();

  31. // 由于LinkedList是双向链表;而表头header不包含数据。

  32. // 因而,这里返回表头header的前一个节点所包含的数据。

  33. return header.previous.element;

  34. }

  35. // 删除LinkedList的第一个元素

  36. public E removeFirst() {

  37. return remove(header.next);

  38. }

  39. // 删除LinkedList的最后一个元素

  40. public E removeLast() {

  41. return remove(header.previous);

  42. }

  43. // 将元素添加到LinkedList的起始位置

  44. public void addFirst(E e) {

  45. addBefore(e, header.next);

  46. }

  47. // 将元素添加到LinkedList的结束位置

  48. public void addLast(E e) {

  49. addBefore(e, header);

  50. }

  51. // 判断LinkedList是否包含元素(o)

  52. public boolean contains(Object o) {

  53. return indexOf(o) != -1;

  54. }

  55. // 返回LinkedList的大小

  56. public int size() {

  57. return size;

  58. }

  59. // 将元素(E)添加到LinkedList中

  60. public boolean add(E e) {

  61. // 将节点(节点数据是e)添加到表头(header)之前。

  62. // 即,将节点添加到双向链表的末端。

  63. addBefore(e, header);

  64. return true;

  65. }

  66. // 从LinkedList中删除元素(o)

  67. // 从链表开始查找,如存在元素(o)则删除该元素并返回true;

  68. // 否则,返回false。

  69. public boolean remove(Object o) {

  70. if (o==null) {

  71. // 若o为null的删除情况

  72. for (Entry e = header.next; e != header; e = e.next) {

  73. if (e.element==null) {

  74. remove(e);

  75. return true;

  76. }

  77. }

  78. } else {

  79. // 若o不为null的删除情况

  80. for (Entry e = header.next; e != header; e = e.next) {

  81. if (o.equals(e.element)) {

  82. remove(e);

  83. return true;

  84. }

  85. }

  86. }

  87. return false;

  88. }

  89. // 将“集合©”添加到LinkedList中。

  90. // 实际上,是从双向链表的末尾开始,将“集合©”添加到双向链表中。

  91. public boolean addAll(Collection<? extends E> c) {

  92. return addAll(size, c);

  93. }

  94. // 从双向链表的index开始,将“集合©”添加到双向链表中。

  95. public boolean addAll(int index, Collection<? extends E> c) {

  96. if (index < 0 || index > size)

  97. throw new IndexOutOfBoundsException("Index: "+index+

  98. ", Size: "+size);

  99. Object[] a = c.toArray();

  100. // 获取集合的长度

  101. int numNew = a.length;

  102. if (numNew==0)

  103. return false;

  104. modCount++;

  105. // 设置“当前要插入节点的后一个节点”

  106. Entry successor = (index==size ? header : entry(index));

  107. // 设置“当前要插入节点的前一个节点”

  108. Entry predecessor = successor.previous;

  109. // 将集合©全部插入双向链表中

  110. for (int i=0; i<numNew; i++) {

  111. Entry e = new Entry((E)a[i], successor, predecessor);

  112. predecessor.next = e;

  113. predecessor = e;

  114. }

  115. successor.previous = predecessor;

  116. // 调整LinkedList的实际大小

  117. size += numNew;

  118. return true;

  119. }

  120. // 清空双向链表

  121. public void clear() {

  122. Entry e = header.next;

  123. // 从表头开始,逐个向后遍历;对遍历到的节点执行一下操作:

  124. // (01) 设置前一个节点为null

  125. // (02) 设置当前节点的内容为null

  126. // (03) 设置后一个节点为“新的当前节点”

  127. while (e != header) {

  128. Entry next = e.next;

  129. e.next = e.previous = null;

  130. e.element = null;

  131. e = next;

  132. }

  133. header.next = header.previous = header;

  134. // 设置大小为0

  135. size = 0;

  136. modCount++;

  137. }

  138. // 返回LinkedList指定位置的元素

  139. public E get(int index) {

  140. return entry(index).element;

  141. }

  142. // 设置index位置对应的节点的值为element

  143. public E set(int index, E element) {

  144. Entry e = entry(index);

  145. E oldVal = e.element;

  146. e.element = element;

  147. return oldVal;

  148. }

  149. // 在index前添加节点,且节点的值为element

  150. public void add(int index, E element) {

  151. addBefore(element, (index==size ? header : entry(index)));

  152. }

  153. // 删除index位置的节点

  154. public E remove(int index) {

  155. return remove(entry(index));

  156. }

  157. // 获取双向链表中指定位置的节点

  158. private Entry entry(int index) {

  159. if (index < 0 || index >= size)

  160. throw new IndexOutOfBoundsException("Index: "+index+

  161. ", Size: "+size);

  162. Entry e = header;

  163. // 获取index处的节点。

  164. // 若index < 双向链表长度的1/2,则从前先后查找;

  165. // 否则,从后向前查找。

  166. if (index < (size >> 1)) {

  167. for (int i = 0; i <= index; i++)

  168. e = e.next;

  169. } else {

  170. for (int i = size; i > index; i–)

  171. e = e.previous;

  172. }

  173. return e;

  174. }

  175. // 从前向后查找,返回“值为对象(o)的节点对应的索引”

  176. // 不存在就返回-1

  177. public int indexOf(Object o) {

  178. int index = 0;

  179. if (o==null) {

  180. for (Entry e = header.next; e != header; e = e.next) {

  181. if (e.element==null)

  182. return index;

  183. index++;

  184. }

  185. } else {

  186. for (Entry e = header.next; e != header; e = e.next) {

  187. if (o.equals(e.element))

  188. return index;

  189. index++;

  190. }

  191. }

  192. return -1;

  193. }

  194. // 从后向前查找,返回“值为对象(o)的节点对应的索引”

  195. // 不存在就返回-1

  196. public int lastIndexOf(Object o) {

  197. int index = size;

  198. if (o==null) {

  199. for (Entry e = header.previous; e != header; e = e.previous) {

  200. index–;

  201. if (e.element==null)

  202. return index;

  203. }

  204. } else {

  205. for (Entry e = header.previous; e != header; e = e.previous) {

  206. index–;

  207. if (o.equals(e.element))

  208. return index;

  209. }

  210. }

  211. return -1;

  212. }

  213. // 返回第一个节点

  214. // 若LinkedList的大小为0,则返回null

  215. public E peek() {

  216. if (size==0)

  217. return null;

  218. return getFirst();

  219. }

  220. // 返回第一个节点

  221. // 若LinkedList的大小为0,则抛出异常

  222. public E element() {

  223. return getFirst();

  224. }

  225. // 删除并返回第一个节点

  226. // 若LinkedList的大小为0,则返回null

  227. public E poll() {

  228. if (size==0)

  229. return null;

  230. return removeFirst();

  231. }

  232. // 将e添加双向链表末尾

  233. public boolean offer(E e) {

  234. return add(e);

  235. }

  236. // 将e添加双向链表开头

  237. public boolean offerFirst(E e) {

  238. addFirst(e);

  239. return true;

  240. }

  241. // 将e添加双向链表末尾

  242. public boolean offerLast(E e) {

  243. addLast(e);

  244. return true;

  245. }

  246. // 返回第一个节点

  247. // 若LinkedList的大小为0,则返回null

  248. public E peekFirst() {

  249. if (size==0)

  250. return null;

  251. return getFirst();

  252. }

  253. // 返回最后一个节点

  254. // 若LinkedList的大小为0,则返回null

  255. public E peekLast() {

  256. if (size==0)

  257. return null;

  258. return getLast();

  259. }

  260. // 删除并返回第一个节点

  261. // 若LinkedList的大小为0,则返回null

  262. public E pollFirst() {

  263. if (size==0)

  264. return null;

  265. return removeFirst();

  266. }

  267. // 删除并返回最后一个节点

  268. // 若LinkedList的大小为0,则返回null

  269. public E pollLast() {

  270. if (size==0)

  271. return null;

  272. return removeLast();

  273. }

  274. // 将e插入到双向链表开头

  275. public void push(E e) {

  276. addFirst(e);

  277. }

  278. // 删除并返回第一个节点

  279. public E pop() {

  280. return removeFirst();

  281. }

  282. // 从LinkedList开始向后查找,删除第一个值为元素(o)的节点

  283. // 从链表开始查找,如存在节点的值为元素(o)的节点,则删除该节点

  284. public boolean removeFirstOccurrence(Object o) {

  285. return remove(o);

  286. }

  287. // 从LinkedList末尾向前查找,删除第一个值为元素(o)的节点

  288. // 从链表开始查找,如存在节点的值为元素(o)的节点,则删除该节点

  289. public boolean removeLastOccurrence(Object o) {

  290. if (o==null) {

  291. for (Entry e = header.previous; e != header; e = e.previous) {

  292. if (e.element==null) {

  293. remove(e);

  294. return true;

  295. }

  296. }

  297. } else {

  298. for (Entry e = header.previous; e != header; e = e.previous) {

  299. if (o.equals(e.element)) {

  300. remove(e);

  301. return true;

  302. }

  303. }

  304. }

  305. return false;

  306. }

  307. // 返回“index到末尾的全部节点”对应的ListIterator对象(List迭代器)

  308. public ListIterator listIterator(int index) {

  309. return new ListItr(index);

  310. }

  311. // List迭代器

  312. private class ListItr implements ListIterator {

  313. // 上一次返回的节点

  314. private Entry lastReturned = header;

  315. // 下一个节点

  316. private Entry next;

  317. // 下一个节点对应的索引值

  318. private int nextIndex;

  319. // 期望的改变计数。用来实现fail-fast机制。

  320. private int expectedModCount = modCount;

  321. // 构造函数。

  322. // 从index位置开始进行迭代

  323. ListItr(int index) {

  324. // index的有效性处理

  325. if (index < 0 || index > size)

  326. throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size);

  327. // 若 “index 小于 ‘双向链表长度的一半’”,则从第一个元素开始往后查找;

  328. // 否则,从最后一个元素往前查找。

  329. if (index < (size >> 1)) {

  330. next = header.next;

  331. for (nextIndex=0; nextIndex<index; nextIndex++)

  332. next = next.next;

  333. } else {

  334. next = header;

  335. for (nextIndex=size; nextIndex>index; nextIndex–)

  336. next = next.previous;

  337. }

  338. }

  339. // 是否存在下一个元素

  340. public boolean hasNext() {

  341. // 通过元素索引是否等于“双向链表大小”来判断是否达到最后。

  342. return nextIndex != size;

  343. }

  344. // 获取下一个元素

  345. public E next() {

  346. checkForComodification();

  347. if (nextIndex == size)

  348. throw new NoSuchElementException();

  349. lastReturned = next;

  350. // next指向链表的下一个元素

  351. next = next.next;

  352. nextIndex++;

  353. return lastReturned.element;

  354. }

  355. // 是否存在上一个元素

  356. public boolean hasPrevious() {

  357. // 通过元素索引是否等于0,来判断是否达到开头。

  358. return nextIndex != 0;

  359. }

  360. // 获取上一个元素

  361. public E previous() {

  362. if (nextIndex == 0)

  363. throw new NoSuchElementException();

  364. // next指向链表的上一个元素

  365. lastReturned = next = next.previous;

  366. nextIndex–;

  367. checkForComodification();

  368. return lastReturned.element;

  369. }

  370. // 获取下一个元素的索引

  371. public int nextIndex() {

  372. return nextIndex;

  373. }

  374. // 获取上一个元素的索引

  375. public int previousIndex() {

  376. return nextIndex-1;

  377. }

  378. // 删除当前元素。

  379. // 删除双向链表中的当前节点

  380. public void remove() {

  381. checkForComodification();

  382. Entry lastNext = lastReturned.next;

  383. try {

  384. LinkedList.this.remove(lastReturned);

  385. } catch (NoSuchElementException e) {

  386. throw new IllegalStateException();

  387. }

  388. if (next==lastReturned)

  389. next = lastNext;

  390. else

  391. nextIndex–;

  392. lastReturned = header;

  393. expectedModCount++;

  394. }

  395. // 设置当前节点为e

  396. public void set(E e) {

  397. if (lastReturned == header)

  398. throw new IllegalStateException();

  399. checkForComodification();

  400. lastReturned.element = e;

  401. }

  402. // 将e添加到当前节点的前面

  403. public void add(E e) {

  404. checkForComodification();

  405. lastReturned = header;

  406. addBefore(e, next);

  407. nextIndex++;

  408. expectedModCount++;

  409. }

  410. // 判断 “modCount和expectedModCount是否相等”,依次来实现fail-fast机制。

  411. final void checkForComodification() {

  412. if (modCount != expectedModCount)

  413. throw new ConcurrentModificationException();

  414. }

  415. }

  416. // 双向链表的节点所对应的数据结构。

  417. // 包含3部分:上一节点,下一节点,当前节点值。

  418. private static class Entry {

  419. // 当前节点所包含的值

  420. E element;

  421. // 下一个节点

  422. Entry next;

  423. // 上一个节点

  424. Entry previous;

  425. /**

  426. * 链表节点的构造函数。

  427. * 参数说明:

  428. *   element  —— 节点所包含的数据

  429. *   next      —— 下一个节点

  430. *   previous —— 上一个节点

  431. */

  432. Entry(E element, Entry next, Entry previous) {

  433. this.element = element;

  434. this.next = next;

  435. this.previous = previous;

  436. }

  437. }

  438. // 将节点(节点数据是e)添加到entry节点之前。

  439. private Entry addBefore(E e, Entry entry) {

  440. // 新建节点newEntry,将newEntry插入到节点e之前;并且设置newEntry的数据是e

  441. Entry newEntry = new Entry(e, entry, entry.previous);

  442. newEntry.previous.next = newEntry;

  443. newEntry.next.previous = newEntry;

  444. // 修改LinkedList大小

  445. size++;

  446. // 修改LinkedList的修改统计数:用来实现fail-fast机制。

  447. modCount++;

  448. return newEntry;

  449. }

  450. // 将节点从链表中删除

  451. private E remove(Entry e) {

  452. if (e == header)

  453. throw new NoSuchElementException();

  454. E result = e.element;

  455. e.previous.next = e.next;

  456. e.next.previous = e.previous;

  457. e.next = e.previous = null;

  458. e.element = null;

  459. size–;

  460. modCount++;

  461. return result;

  462. }

  463. // 反向迭代器

  464. public Iterator descendingIterator() {

  465. return new DescendingIterator();

  466. }

  467. // 反向迭代器实现类。

  468. private class DescendingIterator implements Iterator {

  469. final ListItr itr = new ListItr(size());

  470. // 反向迭代器是否下一个元素。

  471. // 实际上是判断双向链表的当前节点是否达到开头

  472. public boolean hasNext() {

  473. return itr.hasPrevious();

  474. }

  475. // 反向迭代器获取下一个元素。

  476. // 实际上是获取双向链表的前一个节点

  477. public E next() {

  478. return itr.previous();

  479. }

  480. // 删除当前节点

  481. public void remove() {

  482. itr.remove();

  483. }

  484. }

  485. // 返回LinkedList的Object[]数组

  486. public Object[] toArray() {

  487. // 新建Object[]数组

  488. Object[] result = new Object[size];

  489. int i = 0;

  490. // 将链表中所有节点的数据都添加到Object[]数组中

  491. for (Entry e = header.next; e != header; e = e.next)

  492. result[i++] = e.element;

  493. return result;

  494. }

  495. // 返回LinkedList的模板数组。所谓模板数组,即可以将T设为任意的数据类型

  496. public  T[] toArray(T[] a) {

  497. // 若数组a的大小 < LinkedList的元素个数(意味着数组a不能容纳LinkedList中全部元素)

  498. // 则新建一个T[]数组,T[]的大小为LinkedList大小,并将该T[]赋值给a。

  499. if (a.length < size)

  500. a = (T[])java.lang.reflect.Array.newInstance(

  501. a.getClass().getComponentType(), size);

  502. // 将链表中所有节点的数据都添加到数组a中

  503. int i = 0;

  504. Object[] result = a;

  505. for (Entry e = header.next; e != header; e = e.next)

  506. result[i++] = e.element;

  507. if (a.length > size)

  508. a[size] = null;

  509. return a;

  510. }

  511. // 克隆函数。返回LinkedList的克隆对象。

  512. public Object clone() {

  513. LinkedList clone = null;

  514. // 克隆一个LinkedList克隆对象

  515. try {

  516. clone = (LinkedList) super.clone();

  517. } catch (CloneNotSupportedException e) {

  518. throw new InternalError();

  519. }

  520. // 新建LinkedList表头节点

  521. clone.header = new Entry(null, null, null);

  522. clone.header.next = clone.header.previous = clone.header;

  523. clone.size = 0;

  524. clone.modCount = 0;

  525. // 将链表中所有节点的数据都添加到克隆对象中

  526. for (Entry e = header.next; e != header; e = e.next)

  527. clone.add(e.element);

  528. return clone;

  529. }

  530. // java.io.Serializable的写入函数

  531. // 将LinkedList的“容量,所有的元素值”都写入到输出流中

  532. private void writeObject(java.io.ObjectOutputStream s)

  533. throws java.io.IOException {

  534. // Write out any hidden serialization magic

  535. s.defaultWriteObject();

  536. // 写入“容量”

  537. s.writeInt(size);

  538. // 将链表中所有节点的数据都写入到输出流中

  539. for (Entry e = header.next; e != header; e = e.next)

  540. s.writeObject(e.element);

  541. }

  542. // java.io.Serializable的读取函数:根据写入方式反向读出

  543. // 先将LinkedList的“容量”读出,然后将“所有的元素值”读出

  544. private void readObject(java.io.ObjectInputStream s)

  545. throws java.io.IOException, ClassNotFoundException {

  546. // Read in any hidden serialization magic

  547. s.defaultReadObject();

  548. // 从输入流中读取“容量”

  549. int size = s.readInt();

  550. // 新建链表表头节点

  551. header = new Entry(null, null, null);

  552. header.next = header.previous = header;

  553. // 从输入流中将“所有的元素值”并逐个添加到链表中

  554. for (int i=0; i<size; i++)

  555. addBefore((E)s.readObject(), header);

  556. }

  557. }

几点总结

关于LinkedList的源码,给出几点比较重要的总结:

1、从源码中很明显可以看出,LinkedList的实现是基于双向循环链表的,且头结点中不存放数据,如下图;

2、注意两个不同的构造方法。无参构造方法直接建立一个仅包含head节点的空链表,包含Collection的构造方法,先调用无参构造方法建立一个空链表,而后将Collection中的数据加入到链表的尾部后面。

3、在查找和删除某元素时,源码中都划分为该元素为null和不为null两种情况来处理,LinkedList中允许元素为null。

4、LinkedList是基于链表实现的,因此不存在容量不足的问题,所以这里没有扩容的方法。

5、注意源码中的Entry entry(int index)方法。该方法返回双向链表中指定位置处的节点,而链表中是没有下标索引的,要指定位置出的元素,就要遍历该链表,从源码的实现中,我们看到这里有一个加速动作。源码中先将index与长度size的一半比较,如果index<size/2,就只从位置0往后遍历到位置index处,而如果index>size/2,就只从位置size往前遍历到位置index处。这样可以减少一部分不必要的遍历,从而提高一定的效率(实际上效率还是很低)。

6、注意链表类对应的数据结构Entry。如下;

[java]  view plain copy 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. // 双向链表的节点所对应的数据结构。

  2. // 包含3部分:上一节点,下一节点,当前节点值。

  3. private static class Entry {

  4. // 当前节点所包含的值

  5. E element;

  6. // 下一个节点

  7. Entry next;

  8. // 上一个节点

  9. Entry previous;

  10. /**

  11. * 链表节点的构造函数。

  12. * 参数说明:

  13. *   element  —— 节点所包含的数据

  14. *   next      —— 下一个节点

  15. *   previous —— 上一个节点

  16. */

  17. Entry(E element, Entry next, Entry previous) {

  18. this.element = element;

  19. this.next = next;

  20. this.previous = previous;

  21. }

  22. }

7、LinkedList是基于链表实现的,因此插入删除效率高,查找效率低(虽然有一个加速动作)。

8、要注意源码中还实现了栈和队列的操作方法,因此也可以作为栈、队列和双端队列来使用。

Vector源码剖析

Vector简介

Vector也是基于数组实现的,是一个动态数组,其容量能自动增长。

Vector是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是相对安全,有些时候还是要加入同步语句来保证线程的安全),可以用于多线程环境。

Vector没有丝线Serializable接口,因此它不支持序列化,实现了Cloneable接口,能被克隆,实现了RandomAccess接口,支持快速随机访问。

Vector源码剖析

==================

Vector的源码如下(加入了比较详细的注释):

[java]  view plain copy

  1. package java.util;

  2. public class Vector

  3. extends AbstractList

  4. implements List, RandomAccess, Cloneable, java.io.Serializable

  5. {

  6. // 保存Vector中数据的数组

  7. protected Object[] elementData;

  8. // 实际数据的数量

  9. protected int elementCount;

  10. // 容量增长系数

  11. protected int capacityIncrement;

  12. // Vector的序列版本号

  13. private static final long serialVersionUID = -2767605614048989439L;

  14. // Vector构造函数。默认容量是10。

  15. public Vector() {

  16. this(10);

  17. }

  18. // 指定Vector容量大小的构造函数

  19. public Vector(int initialCapacity) {

  20. this(initialCapacity, 0);

  21. }

  22. // 指定Vector"容量大小"和"增长系数"的构造函数

  23. public Vector(int initialCapacity, int capacityIncrement) {

  24. super();

  25. if (initialCapacity < 0)

  26. throw new IllegalArgumentException("Illegal Capacity: "+

  27. initialCapacity);

  28. // 新建一个数组,数组容量是initialCapacity

  29. this.elementData = new Object[initialCapacity];

  30. // 设置容量增长系数

  31. this.capacityIncrement = capacityIncrement;

  32. }

  33. // 指定集合的Vector构造函数。

  34. public Vector(Collection<? extends E> c) {

  35. // 获取“集合©”的数组,并将其赋值给elementData

  36. elementData = c.toArray();

  37. // 设置数组长度

  38. elementCount = elementData.length;

  39. // c.toArray might (incorrectly) not return Object[] (see 6260652)

  40. if (elementData.getClass() != Object[].class)

  41. elementData = Arrays.copyOf(elementData, elementCount, Object[].class);

  42. }

  43. // 将数组Vector的全部元素都拷贝到数组anArray中

  44. public synchronized void copyInto(Object[] anArray) {

  45. System.arraycopy(elementData, 0, anArray, 0, elementCount);

  46. }

  47. // 将当前容量值设为 =实际元素个数

  48. public synchronized void trimToSize() {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

this.elementData = new Object[initialCapacity];

  1. // 设置容量增长系数

  2. this.capacityIncrement = capacityIncrement;

  3. }

  4. // 指定集合的Vector构造函数。

  5. public Vector(Collection<? extends E> c) {

  6. // 获取“集合©”的数组,并将其赋值给elementData

  7. elementData = c.toArray();

  8. // 设置数组长度

  9. elementCount = elementData.length;

  10. // c.toArray might (incorrectly) not return Object[] (see 6260652)

  11. if (elementData.getClass() != Object[].class)

  12. elementData = Arrays.copyOf(elementData, elementCount, Object[].class);

  13. }

  14. // 将数组Vector的全部元素都拷贝到数组anArray中

  15. public synchronized void copyInto(Object[] anArray) {

  16. System.arraycopy(elementData, 0, anArray, 0, elementCount);

  17. }

  18. // 将当前容量值设为 =实际元素个数

  19. public synchronized void trimToSize() {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-IckOdPPA-1711959538978)]
[外链图片转存中…(img-1EpBdjhl-1711959538978)]
[外链图片转存中…(img-Pt82zyOB-1711959538978)]
[外链图片转存中…(img-r1PJpyx5-1711959538979)]
[外链图片转存中…(img-HgwKG5IE-1711959538979)]
[外链图片转存中…(img-4eDPon4F-1711959538979)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-dmlWz1lO-1711959538979)]

最后

想要了解更多关于大厂面试的同学可以点赞支持一下,除此之外,我也分享一些优质资源,包括:Android学习PDF+架构视频+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值