开发者

How can I pass the contents of a list to a varargs method?

开发者 https://www.devze.com 2023-04-02 06:40 出处:网络
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,

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开发者_如何学Python 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?


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


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.


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

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号