【问题标题】:Kind of pointer in Java [duplicate]Java中的指针类型[重复]
【发布时间】:2014-09-10 08:44:27
【问题描述】:

我正在尝试执行以下操作:

import java.util.ArrayList;


public class One {

    private ArrayList<Integer> list;

    public One() {
        addString(list);
        sysoutList(list);
    }

    public void sysoutList(ArrayList<Integer> list2) {
        for (int i = 0; i < list2.size(); i++) {
            System.out.println(list2.get(i));
        }
    }

    private void addString(ArrayList<Integer> list2) {
        list2 = new ArrayList<>();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        list2.add(4);
    }

}

问题是,sysoutList() 会抛出 NullPointerException,因为 list2 为空。看来,在 addString() 中初始化列表没有任何效果,因为类变量不能被引用。在 C++ 中我会用指针来解决这个问题,但是在 Java 中我怎么能做到呢?

【问题讨论】:

  • addString方法中去掉list2 = new ArrayList&lt;&gt;();,插入到One构造函数的开头

标签: java pointers reference nullpointerexception


【解决方案1】:

永远记住Java is pass by value

如果您在方法中重新实例化变量,则传递的变量将保持不变。您的示例正是这样做的。

String myValue = "All your variables belong to us";

setValue(myValue);

System.out.println(myValue); //All your variables belong to us

void setValue(String v){
    v = "Hello World!";
}

你应该首先初始化你的变量:

import java.util.ArrayList;


public class One {

    private ArrayList<Integer> list = new ArrayList<Integer>();

    public One() {
        addString(list);
        sysoutList(list);
    }

    public void sysoutList(ArrayList<Integer> list2) {
        for (int i = 0; i < list2.size(); i++) {
            System.out.println(list2.get(i));
        }
    }

    private void addString(ArrayList<Integer> list2) {
        list2.removeAll();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        list2.add(4);
    }

}

列表是一种特殊情况。您可以认为 使用 add() 方法我实际上是在修改变量,因此不应该发生修改。这不是真的,为什么?

那是因为您正在为列表传递引用的值。如果您使用 new 关键字为该引用分配一个新值,您将“松开”附加到它的对象(您不再拥有它的引用)。

但是,如果您修改该对象的属性(例如使用 add() 方法),该对象的引用仍然有效,因此您修改了原始对象。

我们可以做一个类比。

想象一下,你有一个风筝系在一根绳子上。现在您将一个新字符串附加到它并将新创建的字符串传递给朋友。

如果他切断绳子(也就是创建一个new 一个),他会丢失对你的风筝的引用并且他无法触及它。他可以附加一个新的风筝并进行他想要的所有修改(又名add()),但它永远不会是你的风筝。

如果他使用你给他的绳子来接触风筝并修改它,你会收到一个修改过的风筝。

为了在您的情况下保持相似性,您正在使用private ArrayList&lt;Integer&gt; list; 创建一个没有风筝的字符串 (list),然后将其传递给您的朋友创建一个新字符串 (list2)。现在你和你的朋友都有一个没有附加任何东西的字符串。

他创建了一个新风筝并将其连接到他的绳子上 (list2 = new ArrayList&lt;&gt;()),但您的绳子仍然没有连接任何东西。当您尝试放风筝时,您会发现风筝根本不存在(null 参考)。

首先,您必须创建自己的风筝并附上绳子 (private ArrayList&lt;Integer&gt; list = new ArrayList&lt;Integer&gt;();)。当您将它传递给您的朋友时,会附加另一个字符串 (list2)。现在你的朋友可以使用list2来修改你的风筝了。

编辑

关于您的其他问题,如果可以在从构造函数调用的方法中实例化变量,答案是,但必须将此类变量声明为static 如果你想在你的方法之外使用它。

在风筝中,就像您将风筝连接到一根绳子上,您和您的朋友使用同一根绳子对其进行操作(是的,手牵手)。

为你变成:

import java.util.ArrayList;


public class One {

    private static ArrayList<Integer> list;

    public One() {
        addString();
        sysoutList();
    }

    public void sysoutList() {
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }

    private void addString() {
        list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
    }

}

您不需要传递ArrayList,因为您在程序中的任何地方都使用相同的“风筝字符串”。

注意:如果您调用sysoutList() 之前addString(),您仍然会得到NullPointerException,因为列表尚未初始化。

这是一种不好的做法。我强烈建议你改变你的逻辑。

【讨论】:

    【解决方案2】:

    如果你真的想在方法中实例化类变量,由构造函数调用,你可以这样做:

    import java.util.ArrayList;
    
    
    public class One {
    
        private ArrayList<Integer> list;
    
        public One() {
    
            addString();
        }
    
        private void addString() {
            list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
        }
    }
    

    【讨论】:

      【解决方案3】:

      只需实例化您的列表:

      private ArrayList<Integer> list = new ArrayList<>();  //In 4th line
      

      替换上面的:

      private ArrayList<Integer> list;
      

      由于列表未初始化而发生错误。您也可以在构造函数中对其进行初始化。
      这是一个例子

      public One() {
          list = new ArrayList<>();
          addString(list);
          sysoutList(list);
      }
      

      上面的菱形运算符,即&lt;&gt; 在 7 之前的 jdk 中不起作用,您需要为此使用 `。

      【讨论】:

      • OP 还必须删除 addString 方法中的重新实例化
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多