2011-09-02 36 views
5

我有一个使用方法的可变参数功能:如何将列表的内容传递给可变参数方法?

void add(Animal ...); 

现在,而不是做.add(dog, cat),我有数目不详的元素的动物名单,

List<Animal> i = new ArrayList<Animal>(); 
i.add(dog); 
i.add(cat); 

,并要拨打添加具有这个列表的元素。

我想我可以使用一个数组,但是当我做.add(i.toArray())时,它给出了一个编译器错误。

什么是正确的方法来做到这一点?

+0

我不明白这个问题。你创建了自己的方法'add(Animal ...)',但是你调用ArrayList.add(Object)而不是你自己的方法。这是为什么?请使用代码的上下文编辑问题。你的'add'方法中的代码块是什么?如果你唯一的问题是你不能将Object []转换为Animal [],那么按照@Tom的回答。 – aalku

+0

只是对将来的说明:如果您有编译器错误,请复制完整的错误消息以及与此消息相关的源代码行。 –

回答

10

它是:

add(i.toArray(new Animal[i.size()])) 

List.toArray返回Object[],无论在列表中的参数的类型:即使你可能写new List<String>().toArray(),你会得到一个Object[]。但是,version of toArray that takes an array to fill会返回一个正确类型的数组:如果您编写了new List<String>().toArray(new String[0]),您将得到一个String[]。请注意,您传入的数组的大小甚至不必与列表的大小相匹配,尽管确保它的确很好。

这最终是由于泛型的一个轻度棘手的功能。乍一看,你可能会认为String[]List<String>对于它们的基本类型意味着类似的东西 - 一个是字符串数组,另一个是字符串列表。

然而,他们其实是非常不同的。

数组是一种语言原语,并且它的类型已经烘焙到其中。如果您使用了十六进制编辑器并在JVM的内存中查看了一个数组实例,那么您将能够找到(位于附近的某个地方)所保存对象类型的记录。这意味着如果你拿一个未知组件类型的数组的实例,你可以使用find out what that type is。相反,这意味着如果你打算去create an instance of an array,你需要知道你想要什么组件类型。

List,在另一方面,使用泛型,这在Java中与type erasure实施,这意味着,粗略地讲,它是什么,存在于编译器,而不是在运行时(编译器可以检查你做对了,但JVM不能)。这导致了一个简单而有效的实现(一个足够简单的已经被添加到pre-generics Java而无需更改JVM),但它有一些缺点 - 特别是在运行时,无法告诉类型参数在泛型类的任何特定实例上,因为类型参数只存在于编译器中。由于List实例需要处理toArray(),因此它唯一能做的就是创建一个Object[]。它只是不知道使用更具体的类型。看这个

的一种方法是,数组有一个类型参数作为自己类的一部分,而List■找一个类型参数作为自己类型的一部分,因为对象有类,但变量具有类型,您不能从一个对象中获取List的类型实参,只能从保存对象的变量中获得(另外,您也不能从包含数组的变量中获取数组的类型实参(考虑Object[] array = new String[0];),但这并不重要,因为变量可以让你获得一个对象 - 除非它为空)。

熬下来代码,问题是:

public <E> E[] createSimilarlyTypedArray(List<E> list) { 
    Class<E> componentType = list.???; // there is no way to do this 
    return Arrays.newInstance(componentType, list.size()); 
} 
+0

它将使用你的数组,如果它足够大或分配一个新的,如果它不是。 – aalku

+0

当你在没有泛型类型的List上调用i.toArray(new Animal [])时,你会得到一个类型转换异常吗? –

+1

@Benjamin:不,你不会的。尝试运行'阵列。 (“hello”)。toArray(new String [1]);' - 它完美的工作。静态的,这很好,因为'toArray'版本从它的参数中选择了它的类型参数,而不是拥有'List'(奇怪但是正确!),并且动态地,因为在运行时List类型已被删除。 –

0

当我这样做。新增(i.toArray()),它提供了一个错误,是什么做的正确方法 ?

使用foo.addAll(i)然后如果需要将foo转换为数组。

0

您的方法void add(Animal...)需要Animal类的对象或其中包含Animal对象的数组。你给它一个Object类的对象。给列表一个泛型类型,像这样:

List<Animal> animals = new ArrayList<Animal>(); 
animals.add(dog); 
animals.add(cat) 

然后解析列表作为参数,同时将其转换为一个数组,你的方法,像这样:

add(animals.toArray(new Animal[animals.size()]); 

更多的仿制药可以发现Java API

http://download.oracle.com/javase/1,5.0/docs/guide/language/generics.html

+1

不止期待“一个包含Animal对象的数组”,它需要一个自己的类型为Animal []的数组。 'toArray'的零参数形式创建一个包含'Animal'对象的数组 - 一个基本上是'new Object [] {new Animal()}'的数组。然而,所需要的是'new Animal [] {new Animal()}'。阵列和泛型之间的交汇是一个非常危险的水域! –

相关问题