在这里我们介绍一下最简单的链表LinkedList;
看一下add()方法:
public boolean add(E e) { linkLast(e); return true; }
void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
add原理就是:
1.首先获取链表最后一个节点。
2.把新节点插入到最后一个节点之后。
3.linkedList的last属性重新指向最后一个节点。
4.如果这个节点是第一个节点,之前没有节点,那么将linkedList的first的属性指向新节点;如果不是,则将上一个节点的next属性指向该节点。
使用LinkedList构建先进先出队列:
offer()方法入队:使用add()方法插入节点在最后。
public boolean offer(E e) { return add(e); }
poll()方法出队:从链表表头开始移出队列
public E poll() { final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); }
使用LinkedList构建后进先出队列:
push()方法入队:插入节点在first
public void addFirst(E e) { linkFirst(e); } private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
pop()方法出队:从链表表头开始移出队列
public E pop() { return removeFirst(); } public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); } private E unlinkFirst(Node<E> f) { // assert f == first && f != null; final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; if (next == null) last = null; else next.prev = null; size--; modCount++; return element; }
最后需要注意的是:LinkedList是线程不安全的,如果需要线程安全那么请使用synchronized加锁,或者使用vector,或者使用java.util.concurrent包。
如果需要线程遍历List的时候,避免出现ConcurrentModificationException异常,那么有3种解决方式。
1.遍历List的使用synchronized加锁;
2.使用java.util.concurrent包下面的CopyOnWriteArrayList,每次使用List时实际上都是使用的List副本。
3.使用Jdk8中foreach方法,不过该方法只接受lambda表达式
list.forEach(item -> { System.out.println("遍历元素:" + item); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } });