如何将列表的内容传递给可变参数方法?

发布于 2024-12-02 14:26:28 字数 365 浏览 2 评论 0 原文

我有一个使用 varargs 功能的方法:

void add(Animal ...);

现在,我有一个元素数量未知的 Animal 列表,而不是执行 .add(dog, cat)

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

并且想要使用以下元素调用 add这个清单。

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

正确的做法是什么?

I have a method that uses the varargs feature:

void add(Animal ...);

Now, instead of doing .add(dog, cat), I have an Animal list with unknown number of elements,

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

and want to call add with the elements of this list.

I think I could use an array, but when I do .add(i.toArray()), it gives a compiler error.

What is the proper way to do it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

涙—继续流 2024-12-09 14:26:28

它是:

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

List.toArray 返回一个 < code>Object[],无论 List 上的类型参数如何:即使您可能编写 new List().toArray(),您也会得到一个 对象[]。但是,版本的 toArray 需要要填充的数组 返回一个具有正确类型的数组:如果您编写 new List().toArray(new String[0]),您将得到一个 字符串[]。请注意,您传入的数组的大小甚至不必与列表的大小匹配,尽管确保它匹配是一个很好的做法。

这最终是由于泛型的一个有点棘手的特性造成的。乍一看,您可能会认为 String[]List 的基本类型含义相似 - 一个是字符串数组,另一个是列表字符串。

然而,它们实际上是非常不同的。

数组是一种语言原语,并且具有其类型。如果您使用十六进制编辑器查看 JVM 内存中的数组实例,您将能够(在附近的某个地方)找到它所保存的对象类型的记录。这意味着,如果您获取某种未知组件类型的数组实例,您可以 找出该类型是什么。相反,这意味着如果您要访问创建一个数组的实例,你需要知道你想要什么组件类型。

另一方面,List 使用泛型,在 Java 中通过 类型擦除,这意味着,粗略地说,它是编译器中存在的东西,但运行时不存在(编译器可以检查你是否正确,但 JVM 不能)。这导致了一种简单而高效的实现(一种简单到可以在不更改 JVM 的情况下添加到前泛型 Java 中的实现),但它有一些缺点 - 特别是在运行时,无法判断类型参数是什么在泛型类的任何特定实例上都是如此,因为类型参数仅存在于编译器中。因为由 List 实例来处理 toArray(),所以它唯一能做的就是创建一个 Object[]。它只是不知道要使用更具体的类型。

看待这个问题的一种方法是,数组有一个类型参数作为其的一部分,而List有一个类型参数作为其类型的一部分em>,并且由于对象有类,但变量有类型,因此您无法从对象中获取 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());
}

It's:

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

List.toArray returns an Object[], regardless of the type argument on the List: even though you might write new List<String>().toArray(), you will get an Object[]. However, the version of toArray that takes an array to fill returns an array with the correct type: if you write new List<String>().toArray(new String[0]), you will get an String[]. Note that the size of the array you pass in doesn't even have to match the size of the list, although it's good practice to ensure that it does.

This is ultimately due to a mildly tricky feature of generics. At first glance, you might think that String[] and List<String>mean similar things for their base types - one is an array of strings, the other is a list of strings.

However, they are in fact very different.

An array is a language primitive, and has its type baked into it. If you took a hex editor and looked at an array instance in memory in the JVM, you would be able to find (somewhere nearby) a record of the type of objects it holds. That means that if you take an instance of an array of some unknown component type, you can find out what that type is. Conversely, it means that if you're going to create an instance of an array, you need to know what component type you want.

The List, on the other hand, uses generics, which in Java is implemented with type erasure, which means that, roughly speaking, it is something that exists in the compiler, but not at runtime (the compiler can check that you get it right, but the JVM can't). This leads to a simple and efficient implementation (one simple enough to have been added to pre-generics Java without changing the JVM), but it has some shortcomings - in particular, that at runtime, there is no way to tell what the type argument on any particular instance of a generic class is, because type arguments only exist in the compiler. Because it is up to the List instance to handle toArray(), the only thing it can do is create an Object[]. It just doesn't know of a more specific type to use.

One way of looking at this is that arrays have a type argument as part of their class, whereas Lists have a type argument as part of their type, and since objects have classes but variables have types, you can't get the type argument of a List from an object, only from a variable holding an object (as an aside, you also can't get the type argument of an array from a variable holding an array (consider Object[] array = new String[0];), but that doesn't really matter because, the variable lets you get hold of an object - unless it's null).

To boil this down to code, the problem is:

public <E> E[] createSimilarlyTypedArray(List<E> list) {
    Class<E> componentType = list.???; // there is no way to do this
    return Arrays.newInstance(componentType, list.size());
}
暗恋未遂 2024-12-09 14:26:28

当我执行 .add(i.toArray()) 时,它给出错误,正确的方法是什么
去做吗?

使用 foo.addAll(i) ,然后根据需要将 foo 转换为数组。

when I do .add(i.toArray()) it gives an error, what is the proper way
to do it?

Use foo.addAll(i) and then convert foo to an array if need be.

双手揣兜 2024-12-09 14:26:28

您的方法 void add(Animal...) 需要一个 Animal 类的对象或其中包含 Animal 对象的数组。您给它一个包含 Object 类对象的数组。为 List 指定一个泛型类型,如下所示:

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

Your method void add(Animal...) expects a object of the Animal class or a array with Animal objects in it. You give it an array with objects of the Object class. Give the List a generic type like so:

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

Then parse the list as argument, while converting it to an array, to your method like so:

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

More on generics can be found in the Java API

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文