LinkedList学习笔记(JDK1.6)

LinkedList中存储数据的基本结构为java.util.LinkedList.Entry#Entry(私有内部类)

private static class Entry<E> {
	E element;
	Entry<E> next;
	Entry<E> previous;

	Entry(E element, Entry<E> next, Entry<E> previous) {
		this.element = element;
		this.next = next;
		this.previous = previous;
	}
}

其中:previous指向前一个Entry,next指向后一个Entry,element存储当前对象的具体数据E,这个很好理解

那么第一个元素的previous指向哪里?最后一个元素的next又指向哪里?

其实每个LinkedList实例中都包涵有一个叫做header的元素,该元素即作为头又作为尾,使LinkedList的元素首尾相接,形成一个"环"

private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;

/**
 * Constructs an empty list.
 */
public LinkedList() {
	header.next = header.previous = header;
}

header元素中的previous和next都指向自身,其中element为null

简单的看一下add方法

/**
 * Appends the specified element to the end of this list.
 *
 * <p>This method is equivalent to {@link #addLast}.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
	addBefore(e, header);
	return true;
}
private Entry<E> addBefore(E e, Entry<E> entry) {
	Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
	newEntry.previous.next = newEntry;
	newEntry.next.previous = newEntry;
	size++;
	modCount++;
	return newEntry;
}
addBefore方法中第二个元素(entry)是header,根据Entry的构造方法可以看出,新加入的nextEntry元素的next会指向header,previous指向header的previous,而header中的previous默认指向自身,在加入元素后则指向最后一个元素

(指针确实是把双刃剑,这里每个对象两个指针,互相指来指去,让人有点头晕...)

下面通过实际代码检验下:

通过反射可以清楚的看到LinkedList中Entry的指向关系

try {
	LinkedList<String> ll = new LinkedList<String>();
	ll.add("0001");
	ll.add("0002");

	Class<LinkedList> clazz = LinkedList.class;
	//通过反射获取header属性
	Field headerField = clazz.getDeclaredField("header");
	headerField.setAccessible(true);
	Object header = headerField.get(ll);

	Class entryClazz = header.getClass();
	//获取header元素中的element/next/previous
	Field ele = entryClazz.getDeclaredField("element");
	Field next = entryClazz.getDeclaredField("next");
	Field pre = entryClazz.getDeclaredField("previous");
	ele.setAccessible(true);
	next.setAccessible(true);
	pre.setAccessible(true);

	for (int i = 0; i < 3; i++) {
		//当前Entry对象
		System.out.print(header + "[");
		//当前Entry对象previous指向的对象
		System.out.print(pre.get(header) + " -> ");
		//当前Entry对象存储的值
		System.out.print(ele.get(header) + " -> ");
		//当前Entry对象next指向的对象
		System.out.print(next.get(header));
		System.out.println("]");

		header = next.get(header);
	}
} catch (Exception e) {
	e.printStackTrace();
}
首先我们使用一个空的LinkedList,循环打印三次:
java.util.LinkedList$Entry@38910040[java.util.LinkedList$Entry@38910040 -> null -> java.util.LinkedList$Entry@38910040]
java.util.LinkedList$Entry@38910040[java.util.LinkedList$Entry@38910040 -> null -> java.util.LinkedList$Entry@38910040]
java.util.LinkedList$Entry@38910040[java.util.LinkedList$Entry@38910040 -> null -> java.util.LinkedList$Entry@38910040]

可以清楚看到只有一个Entry对象(38910040)header,并指向自身相成一个环形结构

接下来插入一个元素"001":

java.util.LinkedList$Entry@19b8e059[java.util.LinkedList$Entry@38910040 -> null -> java.util.LinkedList$Entry@38910040]
java.util.LinkedList$Entry@38910040[java.util.LinkedList$Entry@19b8e059 -> 0001 -> java.util.LinkedList$Entry@19b8e059]
java.util.LinkedList$Entry@19b8e059[java.util.LinkedList$Entry@38910040 -> null -> java.util.LinkedList$Entry@38910040]
可以看到有两个Entry,分别是header(19b8e059)和存放"001"的Entry(38910040),回过头来再看addBefore方法,就可以理解为:
Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
newEntry.element = e;
newEntry.next = header;
newEntry.previous = header.previous;
newEntry.previous.next = newEntry;
header.previous = newEntry;
newEntry.next.previous = newEntry;
header.next = newEntry;

这时header和我们新增的元素会首尾相接,形成环

最后我们再加入一个元素"002",循环5次:

java.util.LinkedList$Entry@38910040[java.util.LinkedList$Entry@37a786c3 -> null -> java.util.LinkedList$Entry@578088c0]
java.util.LinkedList$Entry@578088c0[java.util.LinkedList$Entry@38910040 -> 0001 -> java.util.LinkedList$Entry@37a786c3]
java.util.LinkedList$Entry@37a786c3[java.util.LinkedList$Entry@578088c0 -> 0002 -> java.util.LinkedList$Entry@38910040]
java.util.LinkedList$Entry@38910040[java.util.LinkedList$Entry@37a786c3 -> null -> java.util.LinkedList$Entry@578088c0]
java.util.LinkedList$Entry@578088c0[java.util.LinkedList$Entry@38910040 -> 0001 -> java.util.LinkedList$Entry@37a786c3]

可以看到有三个Entry对象38910040,578088c0,37a786c3,第一个对象的previous指向header,第二个(最后一个)对象的next指向header,结果与我们预期的一样

另外header在遍历元素过程也有用到,从[header.next, header)不包含header。可以通过判断“当前对象是否等于header”来确定是否遍历完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值