2010-03-20 142 views
-2

我有以下功能。将参数化ArrayList传递给java中的函数

func(ArrayList `<String>`[] name) { ........ } 

该函数填充ArrayList []。 (我不想返回ArrayList[]

但是,在调用者函数中获得的ArrayList[]具有所有ArrayList作为null
例如,

name = new ArrayList[num]; 
func(name); 
System.out.println(name[0]); 

我得到NullPointerExceptionline 3。这是因为line 1,即我不参数化?如果是的话,还有另一种方法可以做到吗?因为java不允许创建参数化的通用数组ArrayList

+0

我已经改正了我的问题,我其实想制造氩数组。 rayList 。 – athena 2010-03-20 07:19:06

回答

1

这显然不是你真正的代码,但是你正在创建一个ArrayLists数组,这可能不是你想要的。你可能只是做:

ArrayList<String> name = new ArrayList(num); 
func(name); 
System.out.println(name.get(0)); 

注意,当您创建ArrayList中,你只指定初始容量,而不是大小(初始项目数)。它的初始大小为0.你的func可以调用add来添加项目。

1

更妙的是(没有打字错误):

ArrayList<String> name = new ArrayList<String>(); 

我建议不要与初始容量参数(NUM)困扰 - 让它空白,它会很好地工作。但打扰与构造函数中的泛型类型的字符串,或编译器会抱怨。

如果你想知道如何使用ArrayList(例如,为什么要使用get()函数),你应该看看the documentation

+2

他为什么不能给出初始容量?它会提高性能,特别是在大型列表中。 – 2010-03-20 06:55:58

+1

我同意它可以提高性能。但是,我从最初的问题来评估,简单性和正确性对于提出原始问题的人来说很重要,而不是表现。 – John 2010-03-20 07:16:44

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步之间执行此操作。

我猜测了一下,因为你的代码不是很准确(它不会生成一个空指针,就像我所知道的那样写得很近)。

编辑:

你会做的方法,新的和用于与分配回路可以在方法内部完成。我更喜欢在同一个地方分配和初始化(不太令人困惑),但如果需要的话,可以将其分开。

+0

foo [i] = new ArrayList 正在函数func中完成。我不明白的是,在函数func返回之前,我可以访问这些元素。例如。名称[0]不为空。但是当我在调用者函数中访问name [0]时,它是空的。 – athena 2010-03-20 07:35:40

+0

你可以发布该方法的实际代码? – TofuBeer 2010-03-20 08:07:04

+0

还有一件事要做的就是将方法的参数标记为final(例如void foo(final List [] bar)),以确保您不会意外地重新分配它而不是仅仅修改内容。 – TofuBeer 2010-03-20 08:29:18

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变量已被分配到填充方法中的东西,但是主要方法中的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年代到数组的元素,但这些对象调用的外部可见方法。原因是尽管填充方法获得了对数组引用的“复制”,但引用本身仍然引用相同的数组对象。这意味着你可以修改数组对象的内部状态,调用者可以看到你所做的任何更改,因为它引用了同一个对象。

下面是第二种方法:

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; 
    } 

} 

(顺便说一句,你一般应尽量避免创建泛型集合的阵列,一个更好的主意是使用一个列表来存储列表自身的EG。 :

List<List<String>> list = new ArrayList<List<String>>(); 
list.add(new ArrayList<String>()); 
list.get(0).add("test"); 
+0

如果它是对于大多数情况来说这并不完美,我会把它标记为-1,因为“方法的参数是通过值传递的。”Java并没有按照价值传递,这不像你所说的那样,但很容易理解Java通过值传递引用,如果它通过值传递,你的代码示例将不起作用,只有基元传递值。 – TofuBeer 2010-03-20 17:58:42

0

new ArrayList<?>[10]给我不兼容的类型然而,new ArrayList[10]作品对我来说