Почему массив не присваивается Iterable?
с Java5 мы можем написать:
Foo[] foos = ...
for (Foo foo : foos)
или просто используя Iterable в цикле for. Это очень удобно.
Однако вы не можете написать общий метод для итерации следующим образом:
public void bar(Iterable<Foo> foos) { .. }
и вызывая его с массивом, поскольку он не является Итерируемым:
Foo[] foos = { .. };
bar(foos); // compile time error
Мне интересно узнать причины этого решения.
Ответы
Ответ 1
Массивы могут реализовывать интерфейсы (Cloneable
и java.io.Serializable
). Так почему бы не Iterable
? Я полагаю, что Iterable
принудительно добавляет метод iterator
, а массивы не реализуют методы. char[]
даже не отменяет toString
. Во всяком случае, массивы ссылок следует считать менее идеальными - используйте List
s. Как комментарии dfa, Arrays.asList
сделает для вас преобразование явно.
(Сказав это, вы можете вызвать clone
на массивы.)
Ответ 2
Массив - это объект, но его элементы могут быть не такими. Массив может содержать примитивный тип типа int, с которым Iterable не справляется. По крайней мере, это то, что я считаю.
Ответ 3
Массивы должны поддерживать Iterable
, они просто этого не делают, по той же причине, что .NET-массивы не поддерживают интерфейс, который позволяет выполнять только произвольный доступ по позиции (только такой интерфейс не определен как стандартный). По сути, в структурах часто есть раздражающие небольшие пробелы в них, что не стоит никого времени исправить. Не имело бы значения, можем ли мы исправить их самим каким-то оптимальным способом, но часто мы не можем.
UPDATE: Чтобы быть беспристрастным, я упомянул .NET-массивы, не поддерживающие интерфейс, поддерживающий произвольный доступ по позиции (см. также мой комментарий). Но в .NET 4.5 этот точный интерфейс был определен и поддерживается массивами и классом List<T>
:
IReadOnlyList<int> a = new[] {1, 2, 3, 4};
IReadOnlyList<int> b = new List<int> { 1, 2, 3, 4 };
Все еще не совсем идеально, потому что измененный интерфейс списка IList<T>
не наследует IReadOnlyList<T>
:
IList<int> c = new List<int> { 1, 2, 3, 4 };
IReadOnlyList<int> d = c; // error
Возможно, есть возможная возможность обратной совместимости с таким изменением.
Если в новых версиях Java есть какой-то прогресс в аналогичных вещах, мне было бы интересно узнать в комментариях!:)
Ответ 4
К сожалению, массивы не 'class
-enough'. Они не реализуют интерфейс Iterable
.
Пока массивы теперь являются объектами, реализующими Clonable и Serializable, я считаю, что массив не является объектом в обычном смысле и не реализует интерфейс.
Причина, по которой вы можете использовать их для каждого цикла, заключается в том, что Sun добавлено в некоторый синтаксический сахар для массивов (это особый случай).
Поскольку массивы начинались как "почти объекты" с Java 1, это было бы слишком радикально для изменения, чтобы сделать их реальными объектами в Java.