【问题标题】:Implementation of removeFirst() method in SLinkedList in javajava中SLinkedList中removeFirst()方法的实现
【发布时间】:2015-03-30 15:16:42
【问题描述】:

我从一本书中获得了以下代码,用于实现单链表。我不明白removeFirst() 方法中的一些代码行,它从LinkedList 中删除了第一个节点。

class ListNode{
    private String element;
    private ListNode next;

    public ListNode(){
        element = null;
        next = null;
    } 
    public ListNode(String s, ListNode n){
        element = s;
        next = n;
    }
    //Access method
    public String getElement(){
        return element;
    }
    public ListNode getNext(){
        return next;
    }
    //Modify method
    public void setNext(ListNode n){
        next = n;
    }
}

public String removeFirst(){
    if(head == null)
        return null;
    else{
        ListNode temp = head;
        head = head.getNext();
        temp.setNext(null);   //Which I don't understand, is it necessary?
        size --;
        return temp.getElement();
    }
}

看来temp.setNext(null);这个语句可以省略。那么为什么会出现在这里,和java中的垃圾回收有什么关系吗?由于我是 Java 新手,有什么建议或想法吗?

【问题讨论】:

  • 因为列表是双向链表。我猜 head.previous 在删除第一个元素后应该为 null。
  • 列表为单链表。
  • 正如@Thinkingcaps 评论中的答案所说:迭代器保留对 ListNodes 的引用。
  • 针对@keuleJ 的评论,我编辑了我的答案。这条线是必要的。

标签: java garbage-collection adt


【解决方案1】:

这取决于您的问题中未包含的链表的整个实现。但是,如果即使从列表中删除对象后,对象仍可能持有对节点的引用,则该行是必要的。

假设我们有一长串节点A -> B -> C -> ...。假设所有这些节点都已从列表中删除,但我们仍然保留对 A 的引用。如果所有节点仍然持有对下一个的引用,这将防止所有节点被垃圾收集。只需将下一个节点设置为null 即可确保只有A 不能被垃圾回收。

链表的实现很可能做意味着可以保留对节点的引用。例如,Iterator 的许多实现都持有对当前节点的引用。

考虑这段代码:

Iterator<String> iterator = list.iterator();
while (i.hasNext()) {
    if ("foo".equals(i.next())) {
        i.remove();
        break;
    }
}
// lots more code

此代码在列表中搜索第一次出现的 String "foo"。如果找到,它会从列表中删除"foo" 并从循环中中断。这样做的问题是 Iterator i 仍然在剩余代码的范围内,并且仍然持有对节点的引用。如果出现break,则此节点可能位于列表的中间。如果不将next 设置为null,这将防止所有后续节点在i 仍在范围内时被垃圾回收,即使列表已被清除。

请注意,无论如何,您通常都应该将迭代器设为本地循环,就像这样

for (Iterator<String> i = list.iterator();;i.hasNext())

【讨论】:

  • 假设我们有一个单链表 A->B->C->D。现在我们在 removeFirst() 方法中定义了一个对 A 的引用的局部变量,并且 A 仍然持有对 B 的引用,但没有设置为 null。并且我们将作为实例变量的head设置为B。那么在调用removeFirst()方法之后,A会被GC收集吗?效果如何?
  • 问问自己,“我可以编写代码来访问 A 吗?”如果答案是否定的,它将被收集。在您的示例中,一旦您退出 removeFirst() method , A 将无法访问并因此被收集。所以答案是No,如果您只是提取已删除节点的值,则无需设置为 null,仅此而已!
【解决方案2】:

让我们假设,节点的单链表是:A --&gt; B --&gt; C --&gt; D,头节点为 A。现在,让我们看看你的 removeFirst() 方法。当它被调用时,if(head == null) 条件不满足,因为我们的头节点“A”不为 NULL。然后它执行else语句,
temp = head //将头引用放入临时变量
head = head.getNext(); //因为我们要删除第一个节点,它是头,所以我们将头设置为下一个节点(即头 - -> next) 这是节点 "B"
现在,要删除 A(第一个节点),我们需要断开 A(前一个头)--> B(当前头)之间的连接,这将由
temp.setNext(null); //so out 链表变为 A B -->C-->D
然后随着一个节点被删除,因此在下一条语句中它将链接的大小减小size--。

我认为我们还将对 NULL 的临时引用设置为 temp=NULL 以使已删除的节点有资格进行垃圾回收。

【讨论】:

  • 即使你不这样做:temp.setNext(null) --- [temp] 很快就会被 GC 收集
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-26
  • 1970-01-01
  • 2012-03-29
  • 2012-12-31
相关资源
最近更新 更多