Почему массив нельзя присвоить Iterable? - PullRequest
172 голосов
/ 21 июля 2009

с Java5 мы можем написать:

Foo[] foos = ...
for (Foo foo : foos) 

или просто используя Iterable в цикле for. Это очень удобно.

Однако вы не можете написать универсальный метод для итерации, подобный этому:

public void bar(Iterable<Foo> foos) { .. }

и вызов его с массивом, поскольку он не является итерируемым:

Foo[] foos = { .. };
bar(foos);  // compile time error 

Я задаюсь вопросом о причинах этого проектного решения.

Ответы [ 4 ]

71 голосов
/ 22 июля 2009

Массивы могут реализовывать интерфейсы (Cloneable и java.io.Serializable). Так почему бы не Iterable? Я думаю, Iterable заставляет добавлять метод iterator, а массивы не реализуют методы. char[] даже не отменяет toString. В любом случае, массивы ссылок следует считать не идеальными - используйте List с. Как прокомментирует dfa, Arrays.asList сделает преобразование за вас явно.

(Сказав это, вы можете вызвать clone для массивов.)

56 голосов
/ 02 февраля 2010

Массив является объектом, но его элементы могут не быть. Массив может содержать тип примитива типа int, с которым Iterable не может справиться. По крайней мере, это то, что я считаю.

16 голосов
/ 07 августа 2009

Массивы должны поддерживать Iterable, они просто не поддерживают, по той же причине, что массивы .NET не поддерживают интерфейс, который обеспечивает произвольный доступ только для чтения по позиции (такой интерфейс не определен как стандартный). По сути, в фреймворках часто есть небольшие пробелы, которые не стоит никому исправлять. Не имеет значения, могли бы мы сами исправить их каким-то оптимальным способом, но часто мы не можем.

ОБНОВЛЕНИЕ: Чтобы быть беспристрастным, я упомянул массивы .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, мне было бы интересно узнать в комментариях! :)

14 голосов
/ 21 июля 2009

К сожалению, массивы не достаточны. Они не реализуют интерфейс Iterable.

Хотя массивы теперь являются объектами, которые реализуют Clonable и Serializable, я считаю, массив не является объектом в обычном смысле и не реализует интерфейс.

Причина, по которой вы можете использовать их в циклах for-each, заключается в том, что Sun добавил немного синтетического сахара для массивов (это особый случай).

Поскольку массивы начинались как «почти объекты» в Java 1, было бы слишком радикально изменить их, чтобы сделать их реальными объектами в Java.

...