Как я могу передать содержимое списка с varargs методом?
У меня есть метод, который использует функцию varargs:
void add(Animal ...);
Теперь вместо того, чтобы делать .add(dog, cat)
, у меня есть список животных с неизвестным числом элементов,
List<Animal> i = new ArrayList<Animal>();
i.add(dog);
i.add(cat);
И хотим вызвать add с элементами этого списка.
Я думаю, что мог бы использовать массив, но когда я делаю это .add(i.toArray())
, он выдает ошибку компилятора.
Как правильно это сделать?
3 ответа:
Это:
add(i.toArray(new Animal[i.size()]))
Список.toArray возвращает
Object[]
, независимо от аргумента типа в списке: даже если вы можете написатьnew List<String>().toArray()
, вы получитеObject[]
. Однако версия toArray, которая принимает массив для заполнения , возвращает массив с правильным типом: если вы напишетеnew List<String>().toArray(new String[0])
, вы получитеString[]
. Обратите внимание, что размер массива, который вы передаете, даже не должен соответствовать размеру списка, хотя это хорошая практика, чтобы гарантировать, что это так.Это в конечном счете это связано с мягко хитрой особенностью дженериков. На первый взгляд, вы можете подумать, что
String[]
иList<String>
означают одно и то же для их базовых типов - один является массивом строк, другой-списком строк.Однако, на самом деле они очень разные.
Массив является примитивом языка и имеет свой тип, запеченный в нем. Если вы возьмете шестнадцатеричный редактор и посмотрите на экземпляр массива в памяти в JVM, вы сможете найти (где-то поблизости) запись типа предметы, которые он держит. Это означает, что если взять экземпляр массива неизвестного типа компонентов, то можно узнать, что это за тип. И наоборот, это означает, что если вы собираетесь создать экземпляр массива, вам нужно знать, какой тип компонента вы хотите.
The
List
, с другой стороны, использует generics, который в Java реализован с типом erasure , что означает, что, грубо говоря, это то, что существует в компиляторе, но не на runtime (компилятор может проверить, что вы все правильно поняли, но JVM не может). Это приводит к простой и эффективной реализации (достаточно простой, чтобы быть добавленной в pre-generics Java без изменения JVM), но у нее есть некоторые недостатки - в частности, что во время выполнения невозможно определить, что такое аргумент типа в любом конкретном экземпляре универсального класса, потому что аргументы типа существуют только в компиляторе. Поскольку это зависит от экземпляраList
для обработкиtoArray()
, единственное, что он можно сделать, это создатьObject[]
. Он просто не знает более конкретного типа для использования.Один из способов рассмотрения этого состоит в том, что массивы имеют аргумент типа как часть их класса , тогда как
List
S имеют аргумент типа как часть их типа , и поскольку объекты имеют классы, а переменные имеют типы, вы не можете получить аргумент типаList
из объекта, только из переменной, содержащей объект (в качестве отступа, вы также не можете получить аргумент типа массива из переменной удержание массива (рассмотримObject[] array = new String[0];
), но это не имеет особого значения, потому что переменная позволяет вам получить объект - если только он не равен null).Чтобы свести это к коду, проблема заключается в следующем:
public <E> E[] createSimilarlyTypedArray(List<E> list) { Class<E> componentType = list.???; // there is no way to do this return Arrays.newInstance(componentType, list.size()); }
Когда я это сделаю .add (i. toArray ()) это дает ошибку, каков правильный путь чтобы сделать это?
Используйте
foo.addAll(i)
, а затем преобразуйте foo в массив, если это необходимо.
Ваш метод
void add(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