对Java垃圾收集器工作原理的困惑(节点+队列) [英] Confusion over how Java's Garbage Collector works (Nodes + Queue)

查看:143
本文介绍了对Java垃圾收集器工作原理的困惑(节点+队列)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我一直试图在Java中实现LinkedList,Stack和Queue。



对于每一个我使用的节点类,现在我不真的很想讨论我的实现是如何实现的,因为我知道有更好的方法来实现它,我只想关注我的问题。

  public class Node< E> {
私人E数据;
私人节点< E>下一个;
私人节点< E>上一张;

公共节点(E数据){
this.data = data;
this.next = null;
this.prev = null;
}

public E getData(){
return this.data;
}

公共节点< E> getNext(){
return this.next;
}

公共节点< E> getPrev(){
return this.prev;
}

public void setPrev(Node< E> prev){
this.prev = prev;
}

public void setData(E data){
this.data = data;
}

public void setNext(Node< E> next){
this.next = next;






$ b现在有了节点类,了解垃圾收集器如何工作,所以我们可以说这是我的队列类

  public class Queue< E> {
private int size;
私人节点< E>头,尾巴;

public Queue(){
this.size = 0;
this.head = this.tail = null;
}

公共队列(E数据){
节点< E> temp = new Node< E>(data);
this.tail = this.head = temp;
this.size = 0;
}

public boolean enqueue(E data){
Node< E> temp = new Node< E>(data);

if(this.head == null){
this.tail = temp;
this.head = temp;
} else {
temp.setNext(this.head);
this.head.setPrev(temp);
this.head = temp;
}
this.size ++;
返回true;

$ b $ public E dequeue(){
if(this.tail == null)
throw new IndexOutOfBoundsException();
else {
E data = this.tail.getData();
this.tail.setPrev(null);
this.tail = temp;
this.tail.setNext(null);
this.size--;
返回数据;
}
}

public int getSize(){
return this.size;
}

public E peak(){
if(this.tail == null)
throw new IndexOutOfBoundsException();
else
返回this.tail.getData();


public boolean contains(E data){
if(this.head == null)
return false;
else {
for(Node< E> cursor = this.head; cursor!= null; cursor = cursor
.getNext()){
if(cursor.getData ).equals(data))
返回true;
}
}
返回false;




$ b现在我得到了垃圾收集器如何工作的困惑。我听说过,它会清除任何不明显的引用。因此,我一直在我的出队类上获取nullpointerexception,这部分是执行

  this.tail.setNext(null); 

现在,听说垃圾收集器可以工作,没有什么可以引用它,所以我想我自己节点是这样设置的

  head tail 
null < - [1] - >>< - [2 ] - >< - [3] - > null

其中每个节点可指向下一个和以前,所以对于我的出队,我认为我不得不做几件事情。
$ b $ 1)获取数据(这很容易)
$
$ b

  Node< E>获得一个指向前一个的临时节点。 temp = this.tail.getPrev()

3)现在我在这里开始迷路,为了让每个节点不再被引用,我必须除去指向它的所有东西指针,所以这意味着我必须设置为null

  this.tail.setPrev(空); 

因为当我在此之后删除节点时,我无法向后删除该引用 p>

  head tail 
null < - [1] - >< - [2] - > null< - [3] - > null
< - [temp] - > (等于节点[2])

4)将尾部设置为指向temp节点,这是prev节点是

  this.tail = temp; 

不,它应该看起来像这样

 head tail 
null< - [1] - >< - [2] - >(仍然指向[3])null< - [3] - > ; null



5)但是第二个节点仍然指向[3]的内存地址,所以我继续

  this.tail.setNext(null); 

为了让它不再引用任何内存点, GC
null< - [1] - >< - [2] - >删除头尾; null null< - [3] - > null

然而,这部分给我 NullPointerException 当队列中只剩下一个节点时。



现在,我知道我在很多方面可能是错误的,我仍然在学习,但我不确定有多少东西我必须做到每个节点,以确保垃圾收集器得到它,所以任何帮助将做,我需要设置prev和旁边为空?或只有一个?等等,所以任何帮助将不胜感激,谢谢;)

解决方案

代码中存在错误。它与垃圾收集器无关。
您得到 NullPointerException 因为 this.tail null temp = this.tail.getPrev(); ,它是 null 。然后你分配 this.tail = temp; 。下面你会发现 dequeue()的正确实现。
您不必这样做,但也许有些人会认为这是一个很好的做法,可以在删除的节点中将所有内容设置为 null

  public E dequeue(){
if(this.tail == null)
throw new IndexOutOfBoundsException();
else {
E data = this.tail.getData();
节点< E> temp = this.tail;

this.tail = temp.getPrev();
if(this.tail == null){//如果这是最后一个节点
this.head = null;
返回数据;
}
this.tail.setNext(null);

temp.setPrev(null);
temp.setNext(null);

this.size--;
返回数据;




$ p
$ enqueue( )你检查一下emtpy队列。但是在 dequeue()方法中,你可以检查尾部是否相同。这可能有点混乱。你可能应该同时检查 null 。这是对你的程序的额外测试。



构造函数中也有一个错误。 this.size 应设为1而不是0。

 公共队列(E数据){
节点< E> temp = new Node< E>(data);
this.tail = this.head = temp;
this.size = 1;
}


So I been trying to implement LinkedList, Stack, Queue in Java.

For each one i'm using a node class such that, now I don't really want to discuss how my implementation is since I am aware there are better ways to do it, I just want to focus on my question.

public class Node<E> {
    private E data;
    private Node<E> next;
    private Node<E> prev;

    public Node(E data) {
        this.data = data;
        this.next = null;
        this.prev = null;
    }

    public E getData() {
        return this.data;
    }

    public Node<E> getNext() {
        return this.next;
    }

    public Node<E> getPrev() {
        return this.prev;
    }

    public void setPrev(Node<E> prev) {
        this.prev = prev;
    }

    public void setData(E data) {
        this.data = data;
    }

    public void setNext(Node<E> next) {
        this.next = next;
    }
}

Now with the node class there, I keep getting mixed up on how the garbage collector works, so lets say this is my queue class

public class Queue<E> {
    private int size;
    private Node<E> head, tail;

    public Queue() {
        this.size = 0;
        this.head = this.tail = null;
    }

    public Queue(E data) {
        Node<E> temp = new Node<E>(data);
        this.tail = this.head = temp;
        this.size = 0;
    }

    public boolean enqueue(E data) {
        Node<E> temp = new Node<E>(data);

        if (this.head == null) {
            this.tail = temp;
            this.head = temp;
        } else {
            temp.setNext(this.head);
            this.head.setPrev(temp);
            this.head = temp;
        }
        this.size++;
        return true;
    }

    public E dequeue() {
        if (this.tail == null)
            throw new IndexOutOfBoundsException();
        else {
            E data = this.tail.getData();
            this.tail.setPrev(null);
            this.tail = temp;
            this.tail.setNext(null);
            this.size--;
            return data;
        }
    }

    public int getSize() {
        return this.size;
    }

    public E peak() {
        if (this.tail == null)
            throw new IndexOutOfBoundsException();
        else
            return this.tail.getData();
    }

    public boolean contains(E data) {
        if (this.head == null)
            return false;
        else {
            for (Node<E> cursor = this.head; cursor != null; cursor = cursor
                    .getNext()) {
                if (cursor.getData().equals(data))
                    return true;
            }
        }
        return false;
    }
}

Now I am getting how the garbage collector works confused. I have heard, it will clean up any references that don't get pointed too. So I keep getting nullpointerexception on my dequeue class on the part that does the

 this.tail.setNext(null);

now, hearing that for garbage collector to work, nothing can reference it, so I thought to myself my nodes are set up like this

       head          tail
 null<-[1]-><-[2]-><-[3]->null

where each node can point to next and to previous, so for my dequeue I think I have to do few things

1) get the data (that is easy)

2) get a temp Node that points to previous

 Node<E> temp = this.tail.getPrev()

3) now here is where I start to get lost, in order for each node to no longer be referenced, I have to get rid of all things pointer to it, so this means that I must set to null the

this.tail.setPrev(null);

since when I delete the node after that, I can't go backwards to erase that reference

       head               tail
 null<-[1]-><-[2]-> null<-[3]->null
 <-[temp]-> ( equals node [2])

4) Is set tail to point at temp node, which is what the prev node was

this.tail = temp;

no it should look like this

       head   tail    
 null<-[1]-><-[2]->(this still points to [3])    null<-[3]->null

5) but the second node still points to the memory address of [3], so i continue to

this.tail.setNext(null); 

in order to make it so nothing at all references any spot of memory no longer in us,

       head   tail         will be deleted by GC
 null<-[1]-><-[2]->null      null<-[3]->null

However, THIS PART gives me NullPointerException when there is only one node left in queue.

Now, I know I may be wrong on a lot of this, I am still learning, but I am jsut not sure how much stuff I have to do to each node to make sure garbage collector gets it so any help will do, do i need to set both prev and next to null? or only one? etc, so any help will be appreciated, thank you ;)

解决方案

There is bug in your code. It has nothing to do with Garbage Collector. You get NullPointerException because this.tail is null in your example when you have only one node in the queue. You assign temp = this.tail.getPrev(); which is null for one node only. Then you assign this.tail = temp;. Below you will find right implementation of dequeue(). You don't have to, but maybe some people would consider this a good practice to set everything to null in deleted node.

public E dequeue() {
        if (this.tail == null)
            throw new IndexOutOfBoundsException();
        else {
            E data = this.tail.getData();
            Node<E> temp = this.tail;

            this.tail = temp.getPrev();
            if ( this.tail == null ) { // if that was last node
                this.head = null;
                return data;
            }
            this.tail.setNext(null);

            temp.setPrev(null);
            temp.setNext(null);

            this.size--;
            return data;
        }
    }

In the method enqueue() you check head for an emtpy queue. But in the method dequeue() you check tail for the same. It might be little confusing. You should probably check both for null. It's additional test of your program.

There is also a bug in constructor. this.size should be set to 1 not 0.

public Queue(E data) {
        Node<E> temp = new Node<E>(data);
        this.tail = this.head = temp;
        this.size = 1;
    }

这篇关于对Java垃圾收集器工作原理的困惑(节点+队列)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆