【问题标题】:Object value null对象值空
【发布时间】:2012-08-25 17:50:07
【问题描述】:

我是 Java 新手,我正在尝试实现一个链接列表(我确实知道为此目的存在一个列表类,但是从头开始让我了解该语言在内部是如何工作的)

在main方法中,我声明了4个节点并初始化了3个。链表的头节点设置为null。 第一次使用参数head和newNode调用add函数时,head为null,所以我初始化head并将newNode的值赋给它。 在 main 方法中,我希望 head 对象应该从 add 方法中设置新值。但是 head 仍然为空。

我希望能理解为什么会发生这种情况。

抱歉,如果代码不干净,非常感谢!

public class LinkedList
{
    public void add(Node newNode, Node head)
    {
        if(head == null) 
        {
            head = new Node(); 
            head = newNode;              
        }
        else 
        {
            Node temp = new Node(); 
            temp = head; 

            while(temp.next!=null)
            {
                temp = temp.next; 
            }
            temp.next = newNode; 
        }    
    }

    public void traverse(Node head)
    {
        Node temp = new Node(); 
        temp = head; 

        System.out.println("Linked List:: ");

        while(temp.next!=null);  
        {
           System.out.println(" "  + temp.data); 
            temp = temp.next;
        }
    }

    public static void main(String args[])
    {
        Node head = null;
        Node newNode = new Node(null, 5); 
        Node newNode2 = new Node(null, 15); 
        Node newNode3 = new Node(null,30); 

        LinkedList firstList = new LinkedList(); 

        firstList.add(newNode,head); 

       // Part that I don't understand
       // why is head still null here? 

        if(head==null)
        {
         System.out.println("true");
        }

        firstList.traverse(head); 
        firstList.add(newNode2,head); 
        firstList.traverse(head); 
        firstList.add(newNode3,head); 
        firstList.traverse(head); 

    }

}

public class Node
{
    public Node next; 
    public int data; 

    public Node(Node next, int data)
    {
        this.next = next; 
        this.data = data; 
    }

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

}

【问题讨论】:

  • 您可能会发现this post 很有趣。当您在代码顶部写 head = new Node() 时,您更改了参数的本地副本,但这不会更改其在调用代码中的值。
  • 您采取了哪些步骤进行调试?

标签: java null nullpointerexception linked-list


【解决方案1】:

Java 方法参数是按值传递的。

public void add(Node newNode, Node head)
{
    if(head == null) 
    {
        head = new Node(); 
        head = newNode;              
    }
    ...

上面只修改了add范围内的局部变量head。不可能在main 范围内引用局部变量head。如果您希望调用者能够检索新值,也许您应该返回该值。


老实说,面向对象编程的一个主要原则是封装LinkedListhead 理想情况下应该是内部维护的字段。为什么它应该是一个单独的部分?如果您真的希望将head 隔离,那么为什么traverseadd 不是静态的?您应该尝试修改您的设计。我决定重写你的代码here

final class List {

  private Node head;

  public void add(final Node node) {
    if (head == null) {
      head = new Node();
    }
    Node cur;
    for (cur = head; cur.next != null; cur = cur.next)
      ;
    cur.next = node;
  }

  public String toString() {
    final StringBuilder builder = new StringBuilder("Linked List::");
    for (Node cur = head.next; cur != null; cur = cur.next) {
      builder.append("\n ").append(cur.data);
    }
    return builder.toString();
  }
}

final class Node {

  int data;
  Node next;

  Node(final int data) {
    this.data = data;
  }

  Node() { }
}

...然后,进行测试:

  private static Node[] nodesFor(final int... values) {
    int n = values.length;
    final Node[] nodes = new Node[n];
    while (n > 0) {
      nodes[--n] = new Node(values[n]);
    }
    return nodes;
  }

  public static void main(final String[] argv) {
    final List list = new List();
    for (final Node node : nodesFor(5, 15, 30)) {
      list.add(node);
      System.out.println(list);
    }
  }

【讨论】:

    【解决方案2】:

    我认为问题出在“添加”函数内部。您只是在函数范围内更改“head”的值,而不是在它之外。您可以找到有关 Java 处理传递参数值的方式的有用信息here

    在 Java 中一个好的 LinkedList 实现是here

    【讨论】:

      【解决方案3】:

      使“head”引用另一个节点对调用代码没有影响(java传递引用,在java中是地址的“值”)。

      你需要一个对头部的永久引用,所以让它成为你的类的一个字段:

      private Node head = new Node(); // the head of your Node tree
      
      public void add(Node newNode, Node parent) {
          // add node to parent.
          // for some calls, the parent will be the head
      }
      

      【讨论】:

      • Java 传递,而不是引用;关键是,在 Java 中你从来没有真正直接接触过对象的值(就像你在 C++ 中那样),而只是持有对它的引用。
      【解决方案4】:
          firstList.add(newNode,head); 
      
         /*
          Part you should know is, head is a local variable pointing to null.
          Passing head as parameter doesn't make it feasible to alter this local variable.
          Your check is worthless.
          Make public Node add(Node newNode, Node head) and return head from there.
         */ 
          head=firstList.add(newNode,head);
      
          if(head==null)
          {
           System.out.println("true");
          }
      

      【讨论】:

        【解决方案5】:

        这里可以更好地植入您的链接列表。请注意:

        1. _head 应该是私有成员
        2. 节点是一种内部机制。您应该为 add 方法提供数据参数,而不是 Node 对象
        3. 我写了这个,简单,但基于你的代码,实现

          public class LinkedList{
          private Node _head;
          public void add(int data)
          {               
                  //Understand this code! What happens if _head=null?                 
                  _head=new Node(_head,data); 
                  /*
                       //Use the following code for a "Normal" nodes-order
                       if(_head==null)
                          _head=new Node(null,data);
                       else{
                         Node temp=_head;
                         while( temp.next!=null)
                            temp=temp.next;            
                         temp.next=new Node(null,data); 
                       }
                  */
          }
          public void traverse()
          {
              System.out.println("Linked List:: ");
              Node temp=_head;
              while(temp!=null){
                      System.out.println(" "  + temp.data); 
                      temp = temp.next;
              }
          }
          public LinkedList(){
              _head=null;         //null is our lists anchor
          }
          
          public static void main(String args[])
          {
              LinkedList firstList = new LinkedList(); 
          
              firstList.add(5); 
              firstList.traverse(); 
              firstList.add(15); 
              firstList.traverse(); 
              firstList.add(30); 
              firstList.traverse(); 
          
          }
          

          }

        【讨论】:

        • 排序这种情况是一个逻辑概念。这真的取决于你想用你的代码做什么。我会编辑它以显示另一个选项。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-08
        • 2011-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-14
        • 1970-01-01
        相关资源
        最近更新 更多