如何在Java中的函数中分配空数组?

时间:2014-05-15 00:11:50

标签: java arrays

尝试使用值填充多个数组的函数。很想能够做到这一点:

public class Demo {
  public static void getData(int[] array1, int[] array2)  {
    array1 = new int[5];
    array2 = new int[5];
  }

  public static void main(String[] args)  {
    int[] array1 = null;
    int[] array2 = null;
    getData(array1, array2); 
    System.out.println(array1[0]); // line 11
  }
}
Exception in thread "main" java.lang.NullPointerException
  at Demo.main(Demo.java:11)

这给出NullPointerException,但我不确定原因。我无法在main()中分配数组,因为他们无法事先知道它们有多大。可以使用List或2D数组,但是有没有办法可以在没有?

的情况下执行此操作

4 个答案:

答案 0 :(得分:2)

正如其他几位评论员所提到的,这里的问题是误解了传递参考的概念。根据经验,任何时候你a = ... a Objecta(包括数组),你都在断开名称a来自之前的值,并将其指向您的新值。两者之间没有任何联系,也无法引用array1的过去值。因此,在您的情况下,通过将array2null设置为新值,您不再引用传递给函数的对象。在这种情况下,函数参数是main(),而不是实际的对象,但这不会改变任何内容。

然而,更重要的问题是该怎么办?显然目前的设计是行不通的,但 我们是如何做到的呢?这是一个常见的问题,所以不出所料,有很多可行的选择。

使用静态变量

这里最简单的方法就是确保getData()public class Demo { public static void getData(int[] array1, int[] array2) { array1 = new int[5]; array2 = new int[5]; } public static void main(String[] args) { int[] array1 = null; int[] array2 = null; getData(array1, array2); System.out.println(array1[0]); // line 11 } } 都使用相同的变量,方法是使用静态类变量。虽然容易进行简单的项目,但随着项目规模和范围的扩大,这会很快崩溃并开始引入比解决的问题更多的问题。请谨慎使用。

public class Holder {
  // Should really be private, with constructors/getters/setters
  // but for brevity we'll access them directly here.  Don't
  // take this shortcut in production code
  public int[] array1;
  public int[] array2;
}

public class Demo {
  public static void getData(Holder holder) {
    holder.array1 = new int[5];
    holder.array2 = new int[5];
  }

  public static void main(String[] args)  {
    Holder holder = new Holder();
    getData(holder);
    System.out.println(holder.array1.length+" "+holder.array2.length);
  }
}

使用专用对象,并传递对该对象的引用

或者,我们可以通过构造单个holder对象并传递对它的引用来避免静态变量。然后我们可以自由地更改持有者中的实例变量。

List

使用可调整大小的数据结构

你提到你担心的是你提前知道加载数据的大小,这使得它成为import java.util.*; public class Demo { public static void getData(List<Integer> ls1, List<Integer> ls2) { // bad formatting for brevity, don't do this either ls1.add(1); ls1.add(2); ls1.add(3); ls1.add(4); ls1.add(5); ls2.add(1); ls2.add(2); ls2.add(3); ls2.add(4); ls2.add(5); } public static void main(String[] args) { List<Integer> ls1 = new ArrayList<>(); List<Integer> ls2 = new ArrayList<>(); getData(ls1, ls2); System.out.println(ls1.size()+" "+ls2.size()); } } 或其他数据结构的完美候选者。你还提到你不想这样做,这很好,但确实你确实需要数组 - 它们提供的优势很少,而不是正确的集合类型,还有更多的麻烦。使用可调整大小的数据结构,我们可以单独构造和填充相同的对象。

getData()

将此行为完全划分为适当的对象

在给定特定用例的情况下,上述所有选项都是合理的选择,但与创建正确对象的稳健性,强大功能和代码安全性相比,它们都显得苍白无力,并完全划分了行为。这是什么意思?不是将public class Data { // Again, getters/setters, but at least these are final, that's an improvement public final int[] array1; public final int[] array2; public Data() { array1 = new int[5]; array2 = new int[5]; } } public class Demo { public static void main(String[] args) { Data data = new Data(); System.out.println(data.array1.length+" "+data.array2.length); } } 方法应用于某些现有变量,而是将变量和逻辑组合成一个对象 - 这是面向对象编程的核心租户。

main()

通过使用专用类,我们隐藏了从调用者构建此数据的逻辑。相反,Data()方法只是构造一个{{1}}对象,并且可以简单地通过构造它现在拥有所需数据的对象来信任。无需担心引用,数组大小或其他任何内容;所有这些决定都在内部正确处理,并远离来电者。

答案 1 :(得分:0)

array1 = new int[5];
array2 = new int[5];//this will create variable in function body scope

这就是你得到空指针的原因

尝试:

public static void main(String[] args)  {
    int[] array1 = new int[5];
    int[] array2 = new int[5];
    getData(array1, array2); 
}

public static void getData(int[] array1, int[] array2)  {
    // fill array1 and array2 with data
}

你试图实现它的方式,在Java中不是一种可能的方式

答案 2 :(得分:0)

Java将始终将引用传递给main中声明的数组,因此不初始化它将始终获得NPE。我认为你应该只使用List,因为你需要你的方法来定义大小。如果您需要将最终输出作为数组,只需转换为数组。

答案 3 :(得分:-2)

你可以创建一个长度为0的数组:

public void getData(int[] array1, int[] array2)  {
   array1 = new int[5];
   array2 = new int[5];
}
public void main(String[] args)  {
   int[] array1 = new int[0];
   int[] array2 = new int[0];
getData(array1, array2); 
}
// fill array1 and array2 with data