引子:
最近工作不是太忙,项目开发任务也大多完成了,于是又回过头来复习一些Java基础。刚刚,正好看到第15章——泛型,看到了15.2.2小节——一个堆栈类 部分的一段代码。突然想起来,自己很久之前看到这里的时候,对这段代码不是很理解,于是就仔细研究了一下这段代码,并且将自己的理解分享出来,希望能帮到有疑惑的朋友。
代码:
该段代码位于《Think In Java》第四版 P625。
public class LinkedStack<T> {
private static class Node<N> {
private N item;
private Node<N> next;
public Node() { }
public Node(N item, Node<N> next) {
this.item = item;
this.next = next;
}
public boolean end() {
return item == null && next == null;
}
}
private Node<T> top = new Node<>();
public void push(T item) {
top = new Node<>(item, top);
}
public T pop() {
T result = top.item;
if (!top.end()) {
top = top.next;
}
return result;
}
public static void main(String[] args) {
LinkedStack<String> lss = new LinkedStack<>();
for (String s : "Phasers on sun!".split(" ")) {
lss.push(s);
}
String s;
while ((s = lss.pop()) != null) {
System.out.println(s);
}
}
}
分析:
以上就是该段代码,咱们就按照其main方法的执行流程来进行分析。
首先,main方法的第一行代码,声明了一个LinkedStack 对象,没有其他操作;
for循环部分,循环执行了push()方法,其要点之一就是这里,我们看push()方法的源码:
public void push(T item) {
top = new Node<>(item, top);
}
// Node的含参构造方式
public Node(N item, Node<N> next) {
this.item = item;
this.next = next;
}
push()方法可以拆分为两个步骤:
// 第一步,执行下面这行代码,新创建一个结点,并初始化结点的 item 以及 next
new Node<>(item, top);
// 第二步,将 top 指向 刚刚创建的那个结点
top = new Node<>(item, top);
到这里,咱们看看循环部分,其等价于以下代码:
lss.push(“Phasers”);
lss.push(“on”);
lss.push(“sun!”);
而其实际执行的是:
top = new Node<>(“Phasers”, top);
top = new Node<>(“on”, top);
top = new Node<>(“sun!”, top);
按照我们上面讲的拆分方式,理解以下上面的第一行代码:
// 第一步,执行下面这行代码,新创建一个结点并初始化
new Node<>("Phasers", top);
// 第二步,将 top 指向 刚刚创建的那个结点
top = new Node<>("Phasers", top);
下面我简要地花了一个示意图:
从左向右,演示了结点的创建以及top引用指向的结点变换。这样,咱们第一个push()就完成了~需要注意的是中间,我描述的是“产生了一个新的结点node”,这里这个 node 名称是笔者取的,为了描述方便,从代码中并没有任何地方体现出新创建了一个名为node的结点!
至于后面两个push,,一样的道理,只要理解了上面这张图,我相信朋友们很容易就搞明白的。
如果笔者还有什么地方没有解释清楚的,欢迎留言提出疑问,希望和大家一起进步!