我有以下功能。
func(ArrayList `<String>`[] name) { ........ }
该函数填充ArrayList []。 (我不想退回ArrayList[]
)
但是,在调用者函数中,获得的ArrayList[]
将所有ArrayLists都设为null
。
例如。
name = new ArrayList[num];
func(name);
System.out.println(name[0]);
我在NullPointerException
获得line 3
。这是因为line 1
,即我没有参数化?如果是的话,还有另外一种方法吗?因为java不允许创建参数化ArrayList
的通用数组。
答案 0 :(得分:1)
这显然不是你真正的代码,但你正在创建一个ArrayLists数组,这可能不是你想要的。你可以这样做:
ArrayList<String> name = new ArrayList(num);
func(name);
System.out.println(name.get(0));
请注意,在创建ArrayList时,您只需指定初始容量,而不是大小(初始项目数)。它的初始大小为0.您的func只需调用add即可添加项目。
答案 1 :(得分:1)
更好(没有输入错误):
ArrayList<String> name = new ArrayList<String>();
我建议不要打扰初始容量参数(num) - 只需将其留空即可完美运行。但是做在构造函数中使用泛型类型的String,或者编译器会抱怨。
如果你想知道如何使用ArrayList(例如,为什么要使用get()函数),你应该看看the documentation。
答案 2 :(得分:1)
对于Java中的数组,当你创建它时,所有元素都是0,false或null,具体取决于它们的类型。
所以:
final List<String>[] foo;
foo = new ArrayList<String>[10];
foo[0].add("hello"); // crash
崩溃,因为foo = new ArrayList<String>[10];
分配了足够的空间来容纳10 ArrayList<String>
,但它将所有值设置为null。所以你还需要一个额外的步骤:
for(int i = 0; i < foo.length; i++)
{
foo[i] = new ArrayList<String>();
}
我没有编译代码,但很确定它是正确的。您可以在程序的第1步和第2步之间执行此操作。
我猜有点因为你的代码不太准确(它不会像我所知的那样生成一个空指针)。
修改强>
您可以在方法中执行新操作,并且可以在方法内部完成具有分配的for循环。我更喜欢在同一个地方分配和初始化(不那么令人困惑),但如果需要,你可以将其拆分。
答案 3 :(得分:0)
您遇到的问题是由于在Java中,方法的参数是按值传递的。这意味着,每个参数都被有效地“复制”到方法中,这意味着您对参数所做的任何分配只能在方法中可见,并且调用者无法看到。
按照您的示例,您将传入对List<String>
数组的空引用。然后将此引用“复制”到func()
方法中,当func然后为此变量赋值时,它只是正在更新的局部变量,而不是您的调用代码所持有的引用。
以下是一些可编译的代码(基于您的示例),用于演示此问题:
public class Main {
public static void main(String[] args) {
List<String>[] array = null;
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
填充中的println
打印正确的值,因为array
变量已分配给fill方法中的某些内容,但main方法中的println
会抛出NPE,因为只有数组变量的“副本”由func
更改,而不是“真实”变量。
有两种方法可以解决这个问题:在调用代码中实例化数组,或者更改fill()
方法以返回对已创建数组的引用。
以下是第一种方法:
public class Main {
public static void main(String[] args) {
List<String>[] array = (List<String>[])new List[10];
fill(array);
System.out.println("In main(): " + array[0].get(0));
}
public static void fill(List<String>[] array) {
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
}
}
您可能想知道为什么这样可行,因为您仍然将ArrayList
分配给数组的元素,但是这些对象在调用方法之外是可见的。这样做的原因是虽然fill方法获得了对数组的引用的“复制”,但引用本身仍然引用相同的数组 object 。这意味着您可以修改数组对象的内部状态,调用者将看到您所做的任何更改,因为它引用了同一个对象。
以下是第二种方法:
public class Main {
public static void main(String[] args) {
List<String>[] array = fill();
System.out.println("In main(): " + array[0].get(0));
}
public static List<String>[] fill() {
List<String>[] array = (List<String>[])new List[10];
array[0] = new ArrayList<String>();
array[0].add("test");
System.out.println("In fill(): " + array[0].get(0));
return array;
}
}
(顺便说一句,你通常应该尽量避免创建泛型集合数组,更好的办法是使用列表来存储列表本身。例如:
List<List<String>> list = new ArrayList<List<String>>();
list.add(new ArrayList<String>());
list.get(0).add("test");
答案 4 :(得分:0)
new ArrayList<?>[10]
给我不兼容的类型。但是,new ArrayList[10]
对我有用。