Как я могу передать содержимое списка с 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 5

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[]. Он просто не знает более конкретного типа для использования.

Один из способов рассмотрения этого состоит в том, что массивы имеют аргумент типа как часть их класса , тогда как ListS имеют аргумент типа как часть их типа , и поскольку объекты имеют классы, а переменные имеют типы, вы не можете получить аргумент типа 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