博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java集合框架04——LinkedList和源码分析
阅读量:4687 次
发布时间:2019-06-09

本文共 24949 字,大约阅读时间需要 83 分钟。

上一章学习了ArrayList,并分析了其源码,这一章我们将对LinkedList的具体实现进行详细的学习。依然遵循上一章的步骤,先对LinkedList有个整体的认识,然后学习它的源码,深入剖析LinkedList。

LinkedList简介

    首先看看LinkedList与Collection的关系:

                                                 

    LinkedList的继承关系如下:

java.lang.Object     ↳     java.util.AbstractCollection
↳ java.util.AbstractList
↳ java.util.AbstractSequentialList
↳ java.util.LinkedList
public class LinkedList
extends AbstractSequentialList
implements List
, Deque
, Cloneable, java.io.Serializable {}

 LinkedList是一个继承与AbatractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作

        LinkedList实现了List接口,能对它进行队列操作。

        LinkedList实现了Deque接口,即能将LinkedList当作双端队列使用。

        LinkedList实现了Java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。

        LinkedList是非同步的

        这里插一句,简单说一下AbstractSequentialList,因为LinkedList是其子类。

        AbstractSequentialList实现了get(int index)、set(int index, E element)、add(int index, E element)和remove(int index)这些方法。这些接口都是随机访问List的,LinkedList是双向链表,既然它继承与AbstractSequentialList,就相当于已经实现了“get(int index)”这些接口,可以支持随机访问了。

        此外,如果我们需要通过AbstractSequentialList实现一个自己的列表,只需要扩展此类,并提供listIterator()和size()方法的实现即可。若要实现不可修改的列表,则需要实现列表迭代器的hashNext、next、hashPrevious、previous和index方法即可。

    下面先总览一下LinkedList的构造函数和API:

LinkedList的API  boolean       add(E object)  void          add(int location, E object)  boolean       addAll(Collection
collection) boolean addAll(int location, Collection
collection) void addFirst(E object) void addLast(E object) void clear() Object clone() boolean contains(Object object) Iterator
descendingIterator() E element() E get(int location) E getFirst() E getLast() int indexOf(Object object) int lastIndexOf(Object object) ListIterator
listIterator(int location) boolean offer(E o) boolean offerFirst(E e) boolean offerLast(E e) E peek() E peekFirst() E peekLast() E poll() E pollFirst() E pollLast() E pop() void push(E e) E remove() E remove(int location) boolean remove(Object object) E removeFirst() boolean removeFirstOccurrence(Object o) E removeLast() boolean removeLastOccurrence(Object o) E set(int location, E object) int size()
T[] toArray(T[] contents) Object[] toArray()

  LinkedList包含三个重要的成员:first、last和size:first是双向链表的表头,last是双向链表的尾节点,size是双向链表中的节点个数。

LinkedList源码分析(基于JDK1.7)

        下面通过分析LinkedList的源码更加深入的了解LinkedList原理。由于LinkedList是通过双向链表实现的,所以源码也比较容易理解:

1 package java.util;    2     3 /*双向链表*/    4 public class LinkedList
5 extends AbstractSequentialList
6 implements List
, Deque
, Cloneable, java.io.Serializable 7 { 8 /** 9 * 这里先说一下transient关键字的用法: 10 * 一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,可以不必关系具体序列化的过程, 11 * 只要这个类实现了Serilizable接口,这个的所有属性和方法都会自动序列化。但是有种情况是有些属性是不需要序列号的,所以就用到这个关键字。 12 * 只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。 13 */ 14 transient int size = 0; //LinkedList中元素的个数 15 transient Node
first; //链表的头结点 16 transient Node
last; //链表的尾节点 17 18 public LinkedList() { //默认构造函数,创建一个空链表 19 } 20 21 //按照c中的元素生成一个LinkedList 22 public LinkedList(Collection
c) { 23 this(); 24 addAll(c); //将c中的元素添加到空链表的尾部 25 } 26 27 /***************************** 添加头结点 ********************************/ 28 public void addFirst(E e) { 29 linkFirst(e); 30 } 31 32 private void linkFirst(E e) { 33 final Node
f = first; //f指向头结点 34 //生成一个新结点e,其前向指针为null,后向指针为f 35 final Node
newNode = new Node<>(null, e, f); 36 first = newNode; //first指向新生成的结点,f保存着老的头结点信息 37 if (f == null) 38 last = newNode; //如果f为null,则表示整个链表目前是空的,则尾结点也指向新结点 39 else 40 f.prev = newNode; 41 size++; 42 modCount++; //修改次数+1 43 } 44 45 /****************** 添加尾节点,与上面添加头结点原理一样 ******************/ 46 public void addLast(E e) { 47 linkLast(e); 48 } 49 50 void linkLast(E e) { 51 final Node
l = last; 52 final Node
newNode = new Node<>(l, e, null); 53 last = newNode; 54 if (l == null) 55 first = newNode; 56 else 57 l.next = newNode; 58 size++; 59 modCount++; 60 } 61 62 /****************** 在非空节点succ之前插入新节点e ************************/ 63 void linkBefore(E e, Node
succ) { 64 // assert succ != null; //外界调用需保证succ不为null,否则程序会抛出空指针异常 65 final Node
pred = succ.prev; 66 //生成一个新结点e,其前向指针指向pred,后向指针指向succ 67 final Node
newNode = new Node<>(pred, e, succ); 68 succ.prev = newNode; //succ的前向指针指向newNode 69 if (pred == null) 70 //如果pred为null,则表示succ为头结点,此时头结点指向最新生成的结点newNode 71 first = newNode; 72 else 73 //pred的后向指针指向新生成的结点,此时已经完成了结点的插入操作 74 pred.next = newNode; 75 size++; 76 modCount++; 77 } 78 79 /*********************** 删除头结点,并返回头结点的值 *********************/ 80 public E removeFirst() { 81 final Node
f = first; 82 if (f == null) 83 throw new NoSuchElementException(); 84 return unlinkFirst(f); //private方法 85 } 86 87 private E unlinkFirst(Node
f) { 88 // assert f == first && f != null; //需确保f为头结点,且链表不为Null 89 final E element = f.item; //获得节点的值 90 final Node
next = f.next; //获得头结点下一个节点 91 f.item = null; 92 f.next = null; // help GC 93 first = next; 94 if (next == null) 95 //如果next为null,则表示f为last结点,此时链表即为空链表 96 last = null; 97 else 98 //修改next的前向指针,因为first结点的前向指针为null 99 next.prev = null; 100 size--; 101 modCount++; 102 return element; 103 } 104 105 /********************** 删除尾节点,并返回尾节点的值 ********************/ 106 public E removeLast() { 107 final Node
l = last; 108 if (l == null) 109 throw new NoSuchElementException(); 110 return unlinkLast(l); //private方法 111 } 112 113 private E unlinkLast(Node
l) { 114 // assert l == last && l != null; 115 final E element = l.item; 116 final Node
prev = l.prev; 117 l.item = null; 118 l.prev = null; // help GC 119 last = prev; 120 if (prev == null) 121 first = null; 122 else 123 prev.next = null; 124 size--; 125 modCount++; 126 return element; 127 } 128 129 /******************** 删除为空节点x,并返回该节点的值 ******************/ 130 E unlink(Node
x) { 131 // assert x != null; //需确保x不为null,否则后续操作会抛出空指针异常 132 final E element = x.item; 133 final Node
next = x.next; 134 final Node
prev = x.prev; 135 136 if (prev == null) { 137 //如果prev为空,则x结点为first结点,此时first结点指向next结点(x的后向结点) 138 first = next; 139 } else { 140 prev.next = next; //x的前向结点的后向指针指向x的后向结点 141 x.prev = null; //释放x的前向指针 142 } 143 144 if (next == null) { 145 //如果next结点为空,则x结点为尾部结点,此时last结点指向prev结点(x的前向结点) 146 last = prev; 147 } else { 148 next.prev = prev; //x的后向结点的前向指针指向x的前向结点 149 x.next = null; //释放x的后向指针 150 } 151 152 x.item = null; //释放x的值节点,此时x节点可以完全被GC回收 153 size--; 154 modCount++; 155 return element; 156 } 157 158 /********************** 获得头结点的值 ********************/ 159 public E getFirst() { 160 final Node
f = first; 161 if (f == null) 162 throw new NoSuchElementException(); 163 return f.item; 164 } 165 166 /********************** 获得尾结点的值 ********************/ 167 public E getLast() { 168 final Node
l = last; 169 if (l == null) 170 throw new NoSuchElementException(); 171 return l.item; 172 } 173 174 /*************** 判断元素(值为o)是否在链表中 *************/ 175 public boolean contains(Object o) { 176 return indexOf(o) != -1; //定位元素 177 } 178 179 //返回元素个数 180 public int size() { 181 return size; 182 } 183 184 //向链表尾部添加元素e 185 public boolean add(E e) { 186 linkLast(e); 187 return true; 188 } 189 190 /*************** 删除值为o的元素 *************/ 191 public boolean remove(Object o) { 192 if (o == null) { 193 for (Node
x = first; x != null; x = x.next) { 194 if (x.item == null) { //找到即返回 195 unlink(x); 196 return true; 197 } 198 } 199 } else { //o不为空 200 for (Node
x = first; x != null; x = x.next) { 201 if (o.equals(x.item)) { 202 unlink(x); 203 return true; 204 } 205 } 206 } 207 return false; 208 } 209 210 /*************** 将集合e中所有元素添加到链表中 *************/ 211 public boolean addAll(Collection
c) { 212 return addAll(size, c); 213 } 214 //从index开始,向后添加的 215 public boolean addAll(int index, Collection
c) { 216 checkPositionIndex(index); //判断index是否越界 217 218 Object[] a = c.toArray(); //将集合c转换为数组 219 int numNew = a.length; 220 if (numNew == 0) 221 return false; 222 223 Node
pred, succ; 224 if (index == size) { //即index个节点在尾节点后面 225 succ = null; 226 pred = last; //pred指向尾节点 227 } else { 228 succ = node(index); //succ指向第index个节点 229 pred = succ.prev; //pred指向succ的前向节点 230 } 231 232 //for循环结束后,a里面的元素都添加到当前链表里了,向后添加 233 for (Object o : a) { 234 @SuppressWarnings("unchecked") E e = (E) o; 235 Node
newNode = new Node<>(pred, e, null); 236 if (pred == null) 237 first = newNode; //如果pred为null,则succ为头结点 238 else 239 pred.next = newNode; //pred的后向指针指向新节点 240 pred = newNode; //pred指向新节点,即往后移动一个节点,用于下一次循环 241 } 242 243 if (succ == null) { //succ为null表示index为尾节点之后 244 last = pred; 245 } else { 246 //pred表示所有元素添加好之后的最后那个节点,此时pred的后向指针指向之前记录的节点,即index处的节点 247 pred.next = succ; 248 succ.prev = pred; //之前记录的结点指向添加元素之后的最后结点 249 } 250 251 size += numNew; 252 modCount++; 253 return true; 254 } 255 256 /******************** 清空链表 *************************/ 257 public void clear() { 258 for (Node
x = first; x != null; ) { 259 Node
next = x.next; 260 x.item = null; //释放值结点,便于GC回收 261 x.next = null; //释放前向指针 262 x.prev = null; //释放前后指针 263 x = next; //后向遍历 264 } 265 first = last = null; //释放头尾节点 266 size = 0; 267 modCount++; 268 } 269 270 271 /******************* Positional Access Operations ***********************/ 272 273 //获得第index个节点的值 274 public E get(int index) { 275 checkElementIndex(index); 276 return node(index).item; 277 } 278 279 //设置第index元素的值 280 public E set(int index, E element) { 281 checkElementIndex(index); 282 Node
x = node(index); 283 E oldVal = x.item; 284 x.item = element; 285 return oldVal; 286 } 287 288 //在index个节点之前添加新的节点 289 public void add(int index, E element) { 290 checkPositionIndex(index); 291 292 if (index == size) 293 linkLast(element); 294 else 295 linkBefore(element, node(index)); 296 } 297 298 //删除第index个节点 299 public E remove(int index) { 300 checkElementIndex(index); 301 return unlink(node(index)); 302 } 303 304 //判断index是否为链表中的元素下标 305 private boolean isElementIndex(int index) { 306 return index >= 0 && index < size; 307 } 308 309 //判断index是否为链表中的元素下标。。。包含了size 310 private boolean isPositionIndex(int index) { 311 return index >= 0 && index <= size; 312 } 313 314 private String outOfBoundsMsg(int index) { 315 return "Index: "+index+", Size: "+size; 316 } 317 318 private void checkElementIndex(int index) { 319 if (!isElementIndex(index)) 320 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 321 } 322 323 private void checkPositionIndex(int index) { 324 if (!isPositionIndex(index)) 325 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 326 } 327 328 //定位index处的节点 329 Node
node(int index) { 330 // assert isElementIndex(index); 331 //index
> 1)) { 333 Node
x = first; 334 for (int i = 0; i < index; i++) 335 x = x.next; 336 return x; 337 } else { //index>=size/2时,从尾开始找 338 Node
x = last; 339 for (int i = size - 1; i > index; i--) 340 x = x.prev; 341 return x; 342 } 343 } 344 345 /*************************** Search Operations *************************/ 346 347 //返回首次出现指定元素值o的节点索引 348 public int indexOf(Object o) { 349 int index = 0; 350 if (o == null) { 351 for (Node
x = first; x != null; x = x.next) { 352 if (x.item == null) 353 return index; 354 index++; 355 } 356 } else { 357 for (Node
x = first; x != null; x = x.next) { 358 if (o.equals(x.item)) 359 return index; 360 index++; 361 } 362 } 363 return -1; //没有则返回-1 364 } 365 366 //返回最后一次出现指定元素值o的节点索引 367 public int lastIndexOf(Object o) { 368 int index = size; 369 if (o == null) { 370 for (Node
x = last; x != null; x = x.prev) { 371 index--; 372 if (x.item == null) 373 return index; 374 } 375 } else { 376 for (Node
x = last; x != null; x = x.prev) { 377 index--; 378 if (o.equals(x.item)) 379 return index; 380 } 381 } 382 return -1; 383 } 384 385 /***************************** Queue operations ***********************/ 386 //下面是与栈和队列相关的操作了 387 //实现栈的操作,返回第一个元素的值 388 public E peek() { 389 final Node
f = first; 390 return (f == null) ? null : f.item; //不删除 391 } 392 393 //实现队列操作,返回第一个节点 394 public E element() { 395 return getFirst(); 396 } 397 398 //实现栈的操作,弹出第一个节点 399 public E poll() { 400 final Node
f = first; 401 return (f == null) ? null : unlinkFirst(f); //删除 402 } 403 404 //实现队列操作,删除节点 405 public E remove() { 406 return removeFirst(); 407 } 408 409 //添加节点 410 public boolean offer(E e) { 411 return add(e); 412 } 413 414 /************************* Deque operations **********************/ 415 //下面都是和双端队列相关的操作了 416 //添加头结点 417 public boolean offerFirst(E e) { 418 addFirst(e); 419 return true; 420 } 421 422 //添加尾节点 423 public boolean offerLast(E e) { 424 addLast(e); 425 return true; 426 } 427 428 //返回头结点的值 429 public E peekFirst() { 430 final Node
f = first; 431 return (f == null) ? null : f.item; 432 } 433 434 //返回尾节点的值 435 public E peekLast() { 436 final Node
l = last; 437 return (l == null) ? null : l.item; 438 } 439 440 //弹出头结点 441 public E pollFirst() { 442 final Node
f = first; 443 return (f == null) ? null : unlinkFirst(f); //删除 444 } 445 446 //弹出尾节点 447 public E pollLast() { 448 final Node
l = last; 449 return (l == null) ? null : unlinkLast(l); //删除 450 } 451 452 //栈操作,添加头结点 453 public void push(E e) { 454 addFirst(e); 455 } 456 457 //栈操作,删除头结点 458 public E pop() { 459 return removeFirst(); 460 } 461 462 //删除第一次出现o的节点 463 public boolean removeFirstOccurrence(Object o) { 464 return remove(o); 465 } 466 467 //删除最后一次出现o的节点 468 public boolean removeLastOccurrence(Object o) { 469 if (o == null) { 470 for (Node
x = last; x != null; x = x.prev) { 471 if (x.item == null) { 472 unlink(x); 473 return true; 474 } 475 } 476 } else { 477 for (Node
x = last; x != null; x = x.prev) { 478 if (o.equals(x.item)) { 479 unlink(x); 480 return true; 481 } 482 } 483 } 484 return false; 485 } 486 487 /************************* ListIterator ***********************/ 488 489 public ListIterator
listIterator(int index) { 490 checkPositionIndex(index); 491 return new ListItr(index); //ListItr是一个双向迭代器 492 } 493 494 //实现双向迭代器 495 private class ListItr implements ListIterator
{ 496 private Node
lastReturned = null;//记录当前节点信息 497 private Node
next; //当前节点的后向节点 498 private int nextIndex; //当前节点的索引 499 private int expectedModCount = modCount; //修改次数 500 501 ListItr(int index) { 502 // assert isPositionIndex(index); 503 next = (index == size) ? null : node(index); 504 nextIndex = index; 505 } 506 507 public boolean hasNext() { 508 return nextIndex < size; 509 } 510 511 public E next() { 512 checkForComodification(); 513 if (!hasNext()) 514 throw new NoSuchElementException(); 515 516 lastReturned = next; //记录当前节点 517 next = next.next; //向后移动一个位置 518 nextIndex++; //节点索引+1 519 return lastReturned.item; //返回当前节点的值 520 } 521 522 public boolean hasPrevious() { 523 return nextIndex > 0; 524 } 525 526 //返回前向节点的值 527 public E previous() { 528 checkForComodification(); 529 if (!hasPrevious()) 530 throw new NoSuchElementException(); 531 532 lastReturned = next = (next == null) ? last : next.prev; 533 nextIndex--; 534 return lastReturned.item; 535 } 536 537 public int nextIndex() { //返回当前节点的索引 538 return nextIndex; 539 } 540 541 public int previousIndex() { //返回当前节点的前一个索引 542 return nextIndex - 1; 543 } 544 545 public void remove() { //删除当前节点 546 checkForComodification(); 547 if (lastReturned == null) 548 throw new IllegalStateException(); 549 550 Node
lastNext = lastReturned.next; 551 unlink(lastReturned); 552 if (next == lastReturned) 553 next = lastNext; 554 else 555 nextIndex--; 556 lastReturned = null; 557 expectedModCount++; 558 } 559 560 public void set(E e) { //设置当前节点的值 561 if (lastReturned == null) 562 throw new IllegalStateException(); 563 checkForComodification(); 564 lastReturned.item = e; 565 } 566 567 //在当前节点前面插入新节点信息 568 public void add(E e) { 569 checkForComodification(); 570 lastReturned = null; 571 if (next == null) 572 linkLast(e); 573 else 574 linkBefore(e, next); 575 nextIndex++; 576 expectedModCount++; 577 } 578 579 final void checkForComodification() { 580 if (modCount != expectedModCount) 581 throw new ConcurrentModificationException(); 582 } 583 } 584 585 private static class Node
{ 586 E item; 587 Node
next; 588 Node
prev; 589 590 Node(Node
prev, E element, Node
next) { 591 this.item = element; 592 this.next = next; 593 this.prev = prev; 594 } 595 } 596 597 //返回前向迭代器 598 public Iterator
descendingIterator() { 599 return new DescendingIterator(); 600 } 601 602 //通过ListItr.previous来提供前向迭代器,方向与原来相反 603 private class DescendingIterator implements Iterator
{ 604 private final ListItr itr = new ListItr(size()); 605 public boolean hasNext() { 606 return itr.hasPrevious(); 607 } 608 public E next() { 609 return itr.previous(); 610 } 611 public void remove() { 612 itr.remove(); 613 } 614 } 615 616 @SuppressWarnings("unchecked") 617 private LinkedList
superClone() { 618 try { 619 return (LinkedList
) super.clone(); 620 } catch (CloneNotSupportedException e) { 621 throw new InternalError(); 622 } 623 } 624 625 //克隆操作,执行浅拷贝,只复制引用,没有复制引用指向的内存 626 public Object clone() { 627 LinkedList
clone = superClone(); 628 629 // Put clone into "virgin" state 630 clone.first = clone.last = null; 631 clone.size = 0; 632 clone.modCount = 0; 633 634 // Initialize clone with our elements 635 for (Node
x = first; x != null; x = x.next) 636 clone.add(x.item); 637 638 return clone; 639 } 640 641 /*************************** toArray ****************************/ 642 //返回LinkedList的Object[]数组 643 public Object[] toArray() { 644 Object[] result = new Object[size]; 645 int i = 0; 646 for (Node
x = first; x != null; x = x.next) 647 result[i++] = x.item; 648 return result; 649 } 650 651 //返回LinkedList的模板数组,存储在a中 652 @SuppressWarnings("unchecked") 653 public
T[] toArray(T[] a) { 654 if (a.length < size) 655 //如果a的大小 < LinkedList的元素个数,意味着数组a不能容纳LinkedList的全部元素 656 //则新建一个T[]数组,T[]的大小为LinkedList大小,并将T[]赋给a 657 a = (T[])java.lang.reflect.Array.newInstance( 658 a.getClass().getComponentType(), size); 659 //如果a大小够容纳LinkedList的全部元素 660 int i = 0; 661 Object[] result = a; 662 for (Node
x = first; x != null; x = x.next) 663 result[i++] = x.item; 664 665 if (a.length > size) 666 a[size] = null; 667 668 return a; 669 } 670 671 private static final long serialVersionUID = 876323262645176354L; 672 673 /************************* Serializable **************************/ 674 //java.io.Serializable的写入函数 675 //将LinkedList的“容量,所有元素值”写入到输出流中 676 private void writeObject(java.io.ObjectOutputStream s) 677 throws java.io.IOException { 678 // Write out any hidden serialization magic 679 s.defaultWriteObject(); 680 681 // Write out size 682 s.writeInt(size); //写入容量 683 684 // Write out all elements in the proper order. 685 for (Node
x = first; x != null; x = x.next) //写入所有数据 686 s.writeObject(x.item); 687 } 688 689 //java.io.Serializable的读取函数:根据写入方式反向读出 690 //先将LinkedList的“容量”读出,然后将“所有元素值”读出 691 @SuppressWarnings("unchecked") 692 private void readObject(java.io.ObjectInputStream s) 693 throws java.io.IOException, ClassNotFoundException { 694 // Read in any hidden serialization magic 695 s.defaultReadObject(); 696 697 // Read in size 698 int size = s.readInt(); //读出容量 699 700 // Read in all elements in the proper order. 701 for (int i = 0; i < size; i++) //读出所有元素值 702 linkLast((E)s.readObject()); 703 } 704 }
View Code

  总结一下:

        1). LinkedList是通过双向链表去实现的。

        2). 从LinkedList的实现方式中可以看出,它不存在容量不足的问题,因为是链表。

        3). LinkedList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写出“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

        4). LinkdedList的克隆函数,即是将全部元素克隆到一个新的LinkedList中。

        5). 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。

        6). LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下标的方法等价:

队列方法       等效方法  add(e)        addLast(e)  offer(e)      offerLast(e)  remove()      removeFirst()  poll()        pollFirst()  element()     getFirst()  peek()        peekFirst()

  7). LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:

栈方法        等效方法  push(e)      addFirst(e)  pop()        removeFirst()  peek()       peekFirst()

LinkedList遍历方式

        LinkedList支持多种遍历方式,建议不要采用随机访问的方式去遍历LinkedList,而采用逐个遍历的方式。下面我们来看看每种遍历方式:

    1). 通过Iterator迭代器遍历

for(Iterator iter = list.iterator(); iter.hasNext();)      iter.next();

 2). 通过快速随机访问遍历

int size = list.size();      for (int i=0; i

    3). 通过for循环遍历

for (Integer integ:list)  ;

 4). 通过pollFirst()pollLast()来遍历

while(list.pollFirst() != null) ;  while(list.pollLast() != null) ;

 5). 通过removeFirst()removeLast()来遍历

while(list.removeFirst() != null)          ;  while(list.removeLast() != null)          ;

下面通过一个测试用例来测试一下这些方法的效率:

import java.util.Iterator;  import java.util.LinkedList;  import java.util.NoSuchElementException;    /*  * @description 测试LinkedList的几种遍历方式和效率  * @author eson_15  */  public class LinkedListThruTest {      public static void main(String[] args) {          // 通过Iterator遍历LinkedList          iteratorLinkedListThruIterator(getLinkedList()) ;                    // 通过快速随机访问遍历LinkedList          iteratorLinkedListThruForeach(getLinkedList()) ;            // 通过for循环的变种来访问遍历LinkedList          iteratorThroughFor2(getLinkedList()) ;            // 通过PollFirst()遍历LinkedList          iteratorThroughPollFirst(getLinkedList()) ;            // 通过PollLast()遍历LinkedList          iteratorThroughPollLast(getLinkedList()) ;            // 通过removeFirst()遍历LinkedList          iteratorThroughRemoveFirst(getLinkedList()) ;            // 通过removeLast()遍历LinkedList          iteratorThroughRemoveLast(getLinkedList()) ;      }            private static LinkedList
getLinkedList() { LinkedList
llist = new LinkedList
(); for (int i=0; i<500000; i++) llist.addLast(i); return llist; } /** * 通过快迭代器遍历LinkedList */ private static void iteratorLinkedListThruIterator(LinkedList
list) { if (list == null) return ; long start = System.currentTimeMillis(); for(Iterator
iter = list.iterator(); iter.hasNext();) iter.next(); long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorLinkedListThruIterator:" + interval+" ms"); } /** * 通过快速随机访问遍历LinkedList */ private static void iteratorLinkedListThruForeach(LinkedList
list) { if (list == null) return ; long start = System.currentTimeMillis(); int size = list.size(); for (int i=0; i
list) { if (list == null) return ; long start = System.currentTimeMillis(); for (Integer integ : list) ; long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughFor2:" + interval+" ms"); } /** * 通过pollFirst()来遍历LinkedList */ private static void iteratorThroughPollFirst(LinkedList
list) { if (list == null) return ; long start = System.currentTimeMillis(); while(list.pollFirst() != null) ; long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughPollFirst:" + interval+" ms"); } /** * 通过pollLast()来遍历LinkedList */ private static void iteratorThroughPollLast(LinkedList
list) { if (list == null) return ; long start = System.currentTimeMillis(); while(list.pollLast() != null) ; long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughPollLast:" + interval+" ms"); } /** * 通过removeFirst()来遍历LinkedList */ private static void iteratorThroughRemoveFirst(LinkedList
list) { if (list == null) return ; long start = System.currentTimeMillis(); try { while(list.removeFirst() != null) ; } catch (NoSuchElementException e) { } long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughRemoveFirst:" + interval+" ms"); } /** * 通过removeLast()来遍历LinkedList */ private static void iteratorThroughRemoveLast(LinkedList
list) { if (list == null) return ; long start = System.currentTimeMillis(); try { while(list.removeLast() != null) ; } catch (NoSuchElementException e) { } long end = System.currentTimeMillis(); long interval = end - start; System.out.println("iteratorThroughRemoveLast:" + interval+" ms"); } }

   测试结果如下:

iteratorLinkedListThruIterator:10 ms  iteratorLinkedListThruForeach:414648 ms  iteratorThroughFor2:10 ms  iteratorThroughPollFirst:8 ms  iteratorThroughPollLast:10 ms  iteratorThroughRemoveFirst:7 ms  iteratorThroughRemoveLast:6 ms

 由此可见,遍历LinkedList时,使用removeFirst()或removeLast()效率最高。但是用它们遍历会删除原始数据;若只是单纯的取数据,而不删除,建议用迭代器方式或者for-each方式。

 

        无论如何,千万不要用随机访问去遍历LinkedList!除非脑门儿被驴给踢了... ...

        LinkedList源码就讨论这么多,如果错误,欢迎留言指正~

转载于:https://www.cnblogs.com/shanheyongmu/p/6434708.html

你可能感兴趣的文章
[解题报告] 100 - The 3n + 1 problem
查看>>
MvvmCross[翻译] 使用Xamarin与MvvmCross完成一个跨平台App
查看>>
Entity Framework 学习高级篇1—改善EF代码的方法(上)
查看>>
027-chown命令
查看>>
Python 线程、进程和协程
查看>>
赛普系统自动拨号
查看>>
platform_device与platform_driver
查看>>
[iOS] iPad与iPhone上各种标准控件的大小
查看>>
动态规划(游船费用问题)
查看>>
[原创]Windows利用BitNami搭建Redmine
查看>>
Mybatis逆向工程配置文件详细介绍(转)
查看>>
Linux命令学习一日一命令(RM)
查看>>
5-1
查看>>
一名3年工作经验的程序员应该具备的技能 -- 转载
查看>>
重回博客园有感
查看>>
【转】java事件监听机制
查看>>
Leetcode 423.从英文中重建数字
查看>>
数组 Arrays类
查看>>
String类的深入学习与理解
查看>>
OLTP vs OLAP
查看>>