Ответ 1
В языке Java и в JVM для массивов имеется множество специальных случаев. Массивы имеют API, но они едва заметны. Как будто массивы объявлены как:
-
implements Cloneable, Serializable
-
public final int length
-
public T[] clone()
гдеT
- тип компонента массива
Однако эти объявления нигде не отображаются ни в каком исходном коде. Подробнее см. JLS 4.10.3 и JLS 10.7. Cloneable
и Serializable
видны через отражение и возвращаются вызовом
Object[].class.getInterfaces()
Возможно, удивительно, что поле length
и метод clone()
не отражаются. Поле length
не является полем; использование его превращается в специальный arraylength
байт-код. Вызов clone()
приводит к фактическому вызову виртуального метода, но если получатель является типом массива, это обрабатывается специально JVM.
Примечательно, что классы массивов не реализуют интерфейс Iterable
.
Когда в Java SE 5 был добавлен цикл расширенного цикла ( "для каждого" ), он поддерживал два разных случая для правого выражения: a Iterable
или тип массива (JLS 14.14.2). Причина в том, что экземпляры и массивы Iterable
обрабатываются совершенно по-разному с помощью инструкции расширенного выражения. Этот раздел JLS дает полное лечение, но проще говоря, ситуация такова.
Для Iterable<T> iterable
код
for (T t : iterable) {
<loop body>
}
- синтаксический сахар для
for (Iterator<T> iterator = iterable.iterator(); iterator.hasNext(); ) {
t = iterator.next();
<loop body>
}
Для массива T[]
код
for (T t : array) {
<loop body>
}
- синтаксический сахар для
for (int i = 0; i < array.length; i++) {
t = array[i];
<loop body>
}
Теперь, почему это было сделано так? Конечно, для массивов возможно реализовать Iterable
, поскольку они уже реализуют другие интерфейсы. Также было бы возможно, чтобы компилятор синтезировал реализацию Iterator
, поддерживаемую массивом. (Существует прецедент для этого. Компилятор уже синтезирует статические методы values()
и valueOf()
, которые автоматически добавляются к каждому классу enum
, как описано в JLS 8.9.3.)
Но массивы - это очень низкоуровневая конструкция, и ожидается, что доступ к массиву с помощью значения int
будет чрезвычайно недорогим. Весьма идиоматично запускать индекс цикла от 0
до длины массива, каждый раз увеличивая на единицу. Этот цикл улучшенного цикла в массиве делает именно это. Если цикл расширенного цикла над массивом был реализован с использованием протокола Iterable
, я думаю, что большинство людей были бы неприятно удивлены, обнаружив, что цикл по массиву связан с начальным вызовом метода и распределением памяти (создание Iterator
), затем двумя вызовами метода на итерацию цикла.
Итак, когда методы по умолчанию были добавлены в Iterable
в Java 8, это вообще не затрагивало массивы.
Как отмечали другие, если у вас есть массив int
, long
, double
или ссылочного типа, можно включить его в поток, используя один из вызовов Arrays.stream()
. Это обеспечивает доступ к map()
, filter()
, forEach()
и т.д.
Было бы неплохо, однако, если бы особые случаи на языке Java и JVM для массивов были заменены реальными конструкциями (наряду с фиксацией множества других проблем, связанных с массивом, таких как плохое управление 2 + мерными массивами, ограничение длины 2 ^ 31 и т.д.). Это предмет исследования "Arrays 2.0" под руководством Джона Роуза. См. John talk на JVMLS 2012 (video, слайды). Идеи, относящиеся к этой дискуссии, включают введение реального интерфейса для массивов, позволяющее библиотекам вставлять доступ к элементу, поддерживать дополнительные операции, такие как нарезка и копирование, и т.д.
Обратите внимание, что все это исследование и будущая работа. Ничего из этих улучшений массива, которые были зафиксированы в дорожной карте Java для любой версии, начиная с этой записи (2016-02-23).