Мне кажется, есть несколько вопросов здесь, которые, возможно, собрались вместе, чтобы создать некоторую путаницу, почему то, что должно быть сделано.
Я думал, что arrays.asList() будет клонировать значения массива в список, и я не понимаю, почему я делаю это снова в конце кода в toArray().
Это, вероятно, именно так, как он набран, но это должно быть ясно, что вы не клонировать Объектами в массиве, но только сделать новый список с ссылками на объекты в массив. Сами объекты будут такими же в массиве, что и в Списке. Я считаю, что это, вероятно, то, что вы имели в виду, но терминология здесь может быть сложной.
Я думал Arrays.asList() будет клонировать значения массива в список ...
не очень. Использование Arrays.asList(T[] items)
предоставит вид на массив items
, который реализует интерфейс java.util.List. Это список фиксированного размера. Вы не можете добавить к нему. Изменения в нем, такие как замена элемента или сортировка на месте, будут переданы в базовый массив. Так что, если вы сделаете это
List<T> l = Arrays.asList(T[] items);
l.set(0, null);
... вы просто установите элемент с индексом 0 фактического массива items
обнулить.
Часть кода, где вы это делаете
List<T> list = new ArrayList<T>(Arrays.asList(items));
может быть написано как это:
List<T> temp = Arrays.asList(items);
List<T> list = new ArrayList<T>(temp);
Первая строка «просмотр», то вторая линия будет эффективно создавать новый java.util.ArrayList
и заполнить его значениями вида в том порядке, в котором они возвращаются своим итератором (который является всего лишь порядком в массиве). Поэтому любые изменения в list
, которые вы сейчас делаете, не меняют массив items
, но имейте в виду, что это все еще только список ссылок. items
и list
ссылаются на те же объекты, только со своим заказом.
Мой вопрос в том, что я уже сделал список из varargs, почему мне нужно делать items.clone() внутри функции toArray.
Здесь может быть две причины. Первое, как сказал CKing в его/ее ответе. Из-за стирания типа и способа реализации массивов в Java (существуют отдельные типы массивов в зависимости от того, является ли это массивом примитивов или ссылок), JVM не будет знать, какой тип массива будет создан, если вы только что назвали toArray()
в списке, который поэтому этот метод имеет тип возврата Object[]
. Поэтому, чтобы получить массив определенного типа, вы должны предоставить массив методу, который можно использовать во время выполнения, чтобы определить тип. Это часть Java API, в которой тот факт, что дженерики работают с помощью стирания типов, не сохраняются во время выполнения, а конкретный способ работы массивов - все это вместе, чтобы удивить разработчика. A bit of abstraction is leaking there.
Но может быть и вторая причина.Если вы поедете, проверьте toArray(T[] a)
method in the Java API, вы увидите эту часть:
Если список соответствует указанному массиву, он возвращается в нем. В противном случае новый массив выделяется типом среды выполнения указанного массива и размером этого списка.
Пусть некоторый код на другой разработчика использует свой метод stableSort так:
T[] items;
// items is created and filled...
T[] sortedItems = stableSort(items);
Если вы не сделали клон, что произошло бы в ваш код будет таким:
List<T> list = new ArrayList<T>(Arrays.asList(items));
// List is now a new ArrayList with the same elements as items
// Do some things with list, such as sorting
T[] result = list.toArray(items);
// Seeing how the list would fit in items, since it has the same number of elements,
// result IS in fact items
Итак, теперь вызывающий код получает sortedItems
обратно, но этот массив является тот же самый массив, в котором он прошел, а именно items
. Видишь ли, varargs - не что иное, как синтаксический сахар для метода с аргументом массива и реализуются как таковые. Возможно, вызывающий не ожидал, что массив, который он передал в качестве аргумента, который должен быть изменен, и может все еще нуждаться в массиве с исходным порядком. Выполнение клона сначала позволит избежать этого и сделать эффект метода менее неожиданным. Хорошая документация по вашим методам имеет решающее значение в таких ситуациях.
Возможно, что код, тестирующий реализацию вашего назначения, хочет вернуть другой массив, и это фактическое приобретение, которое ваш метод придерживается в этом контракте.
EDIT:
На самом деле, ваш код может быть гораздо проще. Вы добьетесь же с:
T[] copy = items.clone();
Arrays.sort(copy);
return copy;
Но ваше задание могло быть на самом деле реализовать алгоритм сортировки самостоятельно, так что этот вопрос может быть спорным.
Разница заключается в том, что 'asList' возвращает' List', а 'toArray' возвращает массив. – Andremoniy
@Andremoniy Я думаю, вопрос в том, почему клон? * – CKing
Это кажется поразительно бессмысленным. Массив обернут как список, который не нужен, но для того, чтобы убедиться, что он завернут в другой список, также не нужен, тогда клонируется массив, который создает массив со всеми элементами, но копирует в него все элементы из список, только что созданный, т.е. те же элементы. –