尝试使用值填充多个数组的函数。很想能够做到这一点:
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数组,但是有没有办法可以在没有?
答案 0 :(得分:2)
正如其他几位评论员所提到的,这里的问题是误解了传递参考的概念。根据经验,任何时候你a = ...
a
Object
是a
(包括数组),你都在断开名称a
来自之前的值,并将其指向您的新值。两者之间没有任何联系,也无法引用array1
的过去值。因此,在您的情况下,通过将array2
和null
设置为新值,您不再引用传递给函数的对象。在这种情况下,函数参数是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