Привет! Раньше во время обучения мы работали с единичными объектами (или примитивными типами). Но что если нам нужно работать не с одним объектом, а с целой группой? Например, мы хотим создать список дней рождения всех сотрудников нашей компании. Он должен содержать, скажем, 30 строк в формате: “Андрей Петров, 25 января”. Здесь нам поможет специальная структура данных — массив. Если сравнить массив с предметами из реальной жизни, то его устройство очень похоже на банковское хранилище с ячейками: Кое-что о массивах в Java - 1 Массив тоже состоит из ячеек. В каждую ячейку ты можешь что-то положить. При этом для доступа к содержимому тебе нужно знать номер ячейки. Создается массив вот так:
public class Main {

   public static void main(String[] args) {

       String [] birthdays = new String[10]; //массив строк Java

   }
}
Здесь мы создали массив на 10 ячеек. Ты сразу можешь обратить внимание на некоторые особенности массива:
  1. Он хранит данные строго определенного типа. Если мы изначально создали массив строк String, мы не сможем хранить в нем что-то другое. Тип данных указывается при создании массива. В этом его отличие от банковской ячейки, в которой клиент может хранить что захочет.

  2. Массив может хранить в себе данные примитивных типов (например, int), строки (String) или объекты одного класса. Точнее даже не сами объекты, а ссылки на эти объекты.

  3. Размер массива обязательно указывается при создании. Указать его позже или изменить размер после создания не получится.
На то, что создается именно массив, Java указывает квадратными скобками [] в обеих частях выражения. Их можно указать до названия переменной-ссылки или после — будет работать и так, и так:
//Java-массивы строк, два варианта синтаксиса
String [] birthdays = new String[10];
String birthdays [] = new String[10];
Если ты хочешь что-то записать в массив, тебе нужно указать номер ячейки, в которой будет записано значение. Номера ячеек массива начинается с 0. Начинать отсчет с нуля — распространенная практика в программировании. Чем быстрее ты к этому привыкнешь, тем лучше :) Кое-что о массивах в Java - 2 То есть если ты хочешь положить какое-то значение в первую ячейку массива, это делается так:
public class Main {

   public static void main(String[] args) {

       String birthdays [] = new String[10];
       birthdays[0] = "Лена Елисеева, 12 марта";
   }
}
Теперь в первой ячейке нашего массива, который содержит дни рождения коллег, хранится строка с днем рождения Лены. По аналогии можно добавить и другие значения:
public class Main {

   public static void main(String[] args) {

       String birthdays [] = new String[10];
       birthdays[0] = "Лена Елисеева, 12 марта";
       birthdays[1] = "Коля Романов, 18 мая";
       birthdays[7] = "Олеся Остапенко, 3 января";
   }
}
Обрати внимание: день рождения Олеси мы добавили в восьмую ячейку (не забыл еще, почему ячейка №7 — восьмая?). Хотя все остальные ячейки у нас не заполнены. Не обязательно записывать значения в массив по порядку — такого ограничения нет. С другой стороны, если будешь записывать по порядку, гораздо проще будет следить за числом свободных и занятых ячеек, и в массиве не будет оставаться “дыр”. Если ты хочешь получить содержимое ячейки массива, как и в случае с банковской, тебе нужно знать ее номер. Делается это так:
public class Main {

   public static void main(String[] args) {

       String birthdays [] = new String[10];
       birthdays[0] = "Лена Елисеева, 12 марта";
       birthdays[1] = "Коля Романов, 18 мая";
       birthdays[7] = "Олеся Остапенко, 3 января";

       String olesyaBirthday = birthdays[7];
       System.out.println(olesyaBirthday);
   }
}
Вывод в консоль: Олеся Остапенко, 3 января Мы создали переменную String и сказали компилятору: “Найди ячейку с индексом 7 в массиве birthdays и присвой значение, которое там хранится, в переменную String olesyaBirthday”. Именно это он и сделал.

Длина массива Java

При работе с массивом ты можешь легко узнать его длину с помощью специального свойства — length.
public class Main {

   public static void main(String[] args) {

       String birthdays [] = new String[10];
       birthdays[0] = "Лена Елисеева, 12 марта";
       birthdays[1] = "Коля Романов, 18 мая";
       birthdays[7] = "Олеся Остапенко, 3 января";

       int birthdaysLength = birthdays.length;
       System.out.println(birthdaysLength);
   }
}
Вывод в консоль: 10 Заметь: в свойстве length хранится размер массива, а не количество заполненных ячеек. Наш массив хранит только 3 значения, но при создании мы указали для него размер = 10. Именно это значение возвращает поле length. Зачем это может пригодиться? Ну, например, если ты захочешь вывести в консоль список всех дней рождения (чтобы проверить, что никого не забыли), это можно сделать в одном простом цикле:
public class Main {

   public static void main(String[] args) {

       String birthdays [] = new String[10];
       birthdays[0] = "Лена Елисеева, 12 марта";
       birthdays[1] = "Коля Романов, 18 мая";
       birthdays[2] = "Вика Игнатова, 12 июля";
       birthdays[3] = "Денис Козлов, 7 сентября";
       birthdays[4] = "Максим Масленников, 9 ноября";
       birthdays[5] = "Роман Баранов, 14 августа";
       birthdays[6] = "Валерия Пяткина, 1 апреля";
       birthdays[7] = "Олеся Остапенко, 3 января";
       birthdays[8] = "Костя Гурко, 19 октября";
       birthdays[9] = "Сережа Наумов, 3 мая";

       for (int i = 0; i < birthdays.length; i++) {
           System.out.println(birthdays[i]);
       }
   }
}
В цикле мы создаем переменную i, которая изначально равна нулю. При каждом проходе мы берем ячейку с индексом i из нашего массива и выводим ее значение на консоль. Цикл сделает 10 итераций, и значения i будут увеличиваться от 0 до 9 — как раз по индексам ячеек нашего массива! Таким образом мы выведем в консоль все значения от birthdays[0] до birthdays[9] На самом деле, есть способы создать массив по-другому. Например, массив чисел int можно создать так:
public class Main {

   public static void main(String[] args) {
       int numbers [] = {7, 12, 8, 4, 33, 79, 1, 16, 2};
   }
}
Этот способ называется “быстрой инициализацией”. Он довольно удобен тем, что мы сразу создаем массив и заполняем его значениями. Не нужно и явно указывать размер массива — поле length при быстрой инициализации заполнится автоматически.
public class Main {

   public static void main(String[] args) {
       int numbers [] = {7, 12, 8, 4, 33, 79, 1, 16, 2};
       System.out.println(numbers.length);
   }
}
Вывод в консоль: 9

Массив объектов Java

Ты уже слышал, что массивы объектов и массивы примитивов по-разному хранятся в памяти. Возьмём, например, массив из трех объектов Cat:
public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public static void main(String[] args) {

       Cat[] cats = new Cat[3];
       cats[0] = new Cat("Томас");
       cats[1] = new Cat("Бегемот");
       cats[2] = new Cat("Филипп Маркович");
   }
}
Здесь нужно понимать несколько вещей:
  1. В случае с примитивами массивы Java хранят множество конкретных значений (например, чисел int). В случае с объектами массив хранит множество ссылок. Массив cats состоит из трех ячеек, в каждой из которых есть ссылка на объект Cat. Каждая из ссылок указывает на адрес в памяти, где этот объект хранится.

  2. Элементы массива в памяти размещаются в едином блоке. Это сделано для более эффективного и быстрого доступа к ним. Таким образом, ссылка cats указывает на блок в памяти, где хранятся все объекты — элементы массива. А cats[0] — на конкретный адрес внутри этого блока.
Кое-что о массивах в Java - 3 Важно понимать, что массив не только может хранить в себе объекты — он и сам является объектом.

Массив массивов или двумерный массив

Исходя из этого, перед нами встает вопрос — а может ли мы создать, например, не массив строк или чисел, а массив массивов? И ответ будет — да, можем! Массив может хранить внутри себя любые объекты, включая другие массивы. Такой массив будет называться двумерным. Если изобразить его на картинке, он будет очень похож на обычную таблицу. Например, мы хотим создать массив, который будет хранить 3 массива чисел int по 10 ячеек в каждом. Выглядеть это будет так:
Кое-что о массивах в Java - 4
Каждая строка изображает массив чисел int. Первый массив содержит числа от 1 до 10, второй — от -1 до -10, третий — набор случайных чисел. Каждый из этих массивов хранится в ячейке нашего двумерного массива. Инициализация двумерного массива в коде выглядит так:
public static void main(String[] args) {
   Cat[][] cats = new Cat[3][5];
}
Наш двумерный массив cats хранит 3 массива по 5 ячеек в каждом. Если мы хотим положить наш объект в третью ячейку второго массива, это делается следующим образом:
public static void main(String[] args) {
   Cat[][] cats = new Cat[3][5];
   cats[1][2] = new Cat("Пушок");
}
[1] указывает на второй массив, а [2] — на третью ячейку этого массива. Поскольку двумерный массив состоит из нескольких массивов, чтобы его обойти и вывести в консоль все значения (или заполнить все ячейки), нам понадобится уже двойной, вложенный цикл:
for (int i = 0; i < cats.length; i++) {
   for (int j = 0; j < cats[i].length; j++) {
       System.out.println(cats[i][j]);
   }
}
Во внешнем цикле (переменная i) мы по очереди обходим все массивы, из которых состоит наш двумерный массив. Во внутреннем цикле (переменная j) мы перебираем все ячейки каждого массива. В итоге первым будет выведен на консоль объект cats[0][0] (первый массив, первая ячейка), вторым — cats[0][1] (первый массив, вторая ячейка). Когда первый массив будет исчерпан — будут выводиться cats[1][0], cats[1][1], cats[1][2] и так далее. Кстати, для двумерных массивов также доступна быстрая инициализация:
int[][] numbers = {{1,2,3}, {4,5,6}, {7,8,9}};
В обычном виде мы бы записали двумерный массив numbers как int[3][3], а такой способ дает нам возможность сразу указать значения. Для чего двумерный массив может понадобиться? Ну, например, с его помощью ты легко можешь воссоздать знаменитую игру “Морской бой”: Кое-что о массивах в Java - 5 Структура игрового поля в “Морском бое” такова, что ее можно легко описать: двумерный массив из 10 массивов, по 10 ячеек в каждом. Ты создаешь два таких массива — для себя и своего противника:
int [][] seaBattle = new int[10][10];
int [][] seaBattle2 = new int[10][10];
Вы заполняете какими-то значениями (например, цифрами или знаками *) те ячейки, в которых располагаются твои корабли, а потом вы с противником по очереди называете номера ячеек:
  • seaBattle[0][2]!
  • Мимо! seaBattle2[2][4]!
  • Ранен!
  • seaBattle2[2][5]!
  • Ранен!
  • seaBattle2[2][6]!,
  • Убит!

Дополнительные материалы о массивах

Хотите знать больше о массивах? Обратите внимание на статьи ниже. Там много интересного и полезного по этой теме.
  1. Массивы в Java — подробная статья о массивах, их создании, инициализации и использовании. С примерами.

  2. Класс Arrays и его использование — в статье описаны некоторые методы класса Array

  3. Массивы первая лекция JavaRush, посвящённая массивам.

  4. Многомерные массивы — подробная статья о многомерных массивах с примерами.

  5. Возвращайте массив нулевой длины, а не null — автор “Эффекктивного программирования” Джошуа Блох рассказывает о том, как лучше возвращать пустые массивы

На этом наше первое знакомство с массивами окончено, но это лишь начало взаимодействия с ними. В следующих лекциях мы увидим интересные способы их применения, а также узнаем какие в Java есть встроенные функции для более удобной работы с этой структурой данных :)