Массивы Java

🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!

Всем привет! Сегодня погрузимся в мир массивов, узнаем об основных методах и операциях, а также о том, какие массивы бывают:)

Массивы: определение

Массивы используются для работы со структурами данных, в которых есть пронумерованные объекты однородного типа. Например, ящики в камере хранения или места в зрительном зале. Иными словами, у нас есть набор пронумерованных ячеек, в каждой хранятся какие-то данные, а доступ к ним осуществляется через обращение к номеру ячейки (индексу).

В Java массив является однородным: все его ячейки содержат элементы одного типа. Например, массив целых чисел может содержать только целый числа (int), массив строк – только строки, массив экземпляров класса Dog – только объекты этого класса. Совмещение этих типов в массиве невозможно.

пояснение к иллюстрации:
1 – представлен массив целых чисел; ячейка с индексом 0 содержит число 7 (выделена синим).
2 – массив строк
3 – массив объекта класса Dog

Объявление массива в Java

Как и любая переменная, массив в Java должен быть объявлен. Сделать это можно двумя способами, они эквивалентны, но первый в большей степени соответствует стилю Java. Второй же – наследие языка C: многие программисты с языка C перешли на Java, и такой способ был сохранен для их удобства.

Таблица, соотносящаяя оба способа:

Объявление массиваПримерыКомментарий
1. dataType[] arrayName;int[] myArray;

Object[] arrayOfObjects;
Рекомендуется объявлять массив именно таким образом, потому что он соответствует стилю Java.
2. dataType arrayName[];int myArray[];

Object arrayOfObjects[];
Способ объявления массива, унаследованный от C/C++.

В обоих случаях dataType – это тип переменных в массиве. В качестве примеров представлено объявление двух массивов – с целыми числами int и с объектами Object. Итак, чтобы объявить массив, нам нужно указать имя массива (ArrayName) и тип его элементов.

Создание массива в Java

Механизм традиционный: мы можем создать массив (то есть зарезервировать для него место в памяти) с помощью оператора new. Вот как это делается:

new typeOfArray[length];

typeOfArray – тип массива, а length – его длина (т. е. количество ячеек), выраженная целым числом (int). Обратите внимание: на этом этапе мы только выделили память под массив, пока еще не связывая его с какой-нибудь ранее объявленной переменной.

Массив сначала объявляется, а затем создаётся:

int[] myArray; // Объявление массива
myArray = new int[10]; // Создание (выделение памяти для) массива, содержащего 10 целых чисел
Run Code

Таким образом мы создаем массив целых чисел с названием myArray, сообщив компилятору, что он состоит из 10 ячеек. Однако чаще используется сокращенный способ, позволюящий создать массив сразу после того, как мы его объявили:

int[] myArray = new int [10]; // Убиваем сразу двух зайцев

Важно: после создания массива с помощью оператора new его ячейки содержат значения по умолчанию. Соответственно, для чисел это 0, для булевых значений – false, а для ссылочных типов – null.

После выполнения приведенной строчки кода мы получим массив из десяти целых чисел, причем в каждой ячейке будет 0.

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

Длина массива – это количество элементов, на которое он рассчитан. Длина массива не может быть изменена после его создания.

Важно: элементы массива нумеруются с нуля! Допустим, в нашем массиве 10 элементов. Это значит, что индекс первого элемента равен 0, а последнего – 9.

Вы можете получить длину массива с помощью метода length:

int[] myArray = new int[10]; // Создаём целочисленный массив из 10 элементов
System.out.println(myArray.length); // Выводим длину массива
Run Code

Вывод:

10

Инициализация массива и доступ к его элементам

Итак, на этапе создания мы получаем массив, заполненный значениями по умолчанию. Настал черёд инициализировать его, то есть заполнить массив определенными значениями. В качестве примера создадим строковый массив для 4 сезонов и заполним его названиями времён года:

String[] seasons = new String[4]; // Объявляем и создаём массив, в каждой ячейка установлено значение по умолчанию (null, потому что строка - ссылочный тип данных)

seasons[0] = "Winter"; // Заполняем первую ячейку, предварительно обратившись к элементу с индексом 0
seasons[1] = "Spring"; // Аналогично для второй ячейки
seasons[2] = "Summer"; // Для третьей - индекс 2
seasons[3] = "Autumn"; // Индекс четвёртой - 3
Run Code

Мы могли бы инициализировать массив другим способом, объединив объявление и инициализацию:

String[] seasons = new String[] {"Winter", "Spring", "Summer", "Autumn"};

Более того, оператор new можно опустить:

String[] seasons = {"Winter", "Spring", "Summer", "Autumn"};

Как вывести массив в консоль?

Элементы массива можно выводить в консоль с помощью цикла for:

String[] seasons = new String {"Winter", "Spring", "Summer", "Autumn"};
for (int i = 0; i < 4; i++) {
System.out.println(seasons[i]);
}
Run Code

Вывод будет таким:

Winter
Spring
Summer
Autumn

Одномерные и многомерные массивы в Java

В Java мы можем даже создать массив массивов!

Массив, с которым мы уже знакомы (int[] myArray = new int[8]), называется одномерным. Соответственно, массив массивов – массив двумерный. Он похож на таблицу, в которой есть номер строки и номер столбца. Можно представить его как матрицу:

Такие массивы нужны, чтобы запрограммировать объекты, имеющую структуру матриц/таблиц (например, шахматная доска).

Многомерный массив объявляется и создается следующим образом:

Int[][] myTwoDimentionalArray = new int[8][8];

Этот массив содержит 64 элемента: myTwoDimentionalArray[0][0], myTwoDimentionalArray[0][1], myTwoDimentionalArray[1][0], myTwoDimentionalArray[1][1] и так далее до myTwoDimentionalArray[7][7].

Но как далеко получится зайти? В Java можно создать массив массивов, массив массивов массивов и т.д… Конечно, трёхмерные и овермногомерные массивы используются крайне редко. Тем не менее, мы можем использовать трехмерный массив, например, для программирования кубика Рубика.

Полезные методы для работы с массивами

Для работы с массивами в Java существует класс java.util.Arrays. Наиболее распространенными операциями над массивами являются инициализация (заполнение элементами), извлечение элементов (по индексу), сортировка и поиск.

Вот три полезных метода:

1. Сортировка массива – метод sort()

Метод void sort(int[] myArray, int fromIndex, int toIndex) сортирует целочисленный массив или подмассив в порядке возрастания.

2. Поиск элемента в массиве – метод binarySearch()

Метод int binarySearch(int[] myArray, int fromIndex, int toIndex, int key) ищет ключевой элемент в отсортированном массиве или подмассиве myArray от fromIndex до toIndex. Если элемент найден, то возвращается его индекс. В противном случае возвращается (-fromIndex)-1.

3. Преобразование массива в строку – метод toString()

Метод String toString(int[] myArray) преобразует массив в строку. Если мы попытаемся вывести в консоль сразу весь массив (System.out.println(myArray)), а не с помощью цикла for (как было раньше рассмотрено), то получим шестнадцаричное число.

Пример использования рассмотренных методов

Давайте создадим массив целых чисел, отобразим его с помощью toString, отсортируем его с помощью метода sort, а затем найдем в нем какое-то число.

class Main {
    public static void main(String[] args) {
        int[] array = {1, 5, 4, 3, 7}; // Объявляем и инициализируем массив
        System.out.println(array); // Пытаемся отобразить наш массив без использования метода toString(). В результате получим шестнадцатеричное число
        System.out.println(Arrays.toString(array)); // Отображаем массив корректно
        Arrays.sort(array, 0, 4); // Сортируем от нулевого до четвертого элемента
        System.out.println(Arrays.toString(array)); // Выводим отсортированный массив
        int key = Arrays.binarySearch(array, 5); // Ищем число 5 в отсортированном массиве. Метод binarySearch() вернет индекс искомого элемента
        System.out.println(key); // Выводим индекс искомого элемента
System.out.println(Arrays.binarySearch(array, 0)); // Попытка найти число, которого нет в массиве, и сразу вывести в консоль
    }
}
Run Code

Вывод:

[I@1540e19d
[1, 5, 4, 3, 7]
[1, 3, 4, 5, 7]
3
-1

В пятой строке вывода мы видим -1. Это недопустимый индекс массива. Он сигнализирует о том, что искомое число (в нашем случае 0) отсутствует в массиве.

Копирование массивов: глубокое и поверхностное

Копирование одномерных массивов

Если нам нужно быстро скопировать одномерный массив, можно вызвать метод clone(). Допустим, у нас есть массив int[] original, вызов int[] copy = original.clone() даст нам другой массив с той же длиной и элементами.

public class SingleDimClone {
    public static void main(String[] args) {
        int[] original = {1, 2, 3};
        int[] clone = original.clone();

        System.out.println("Original: " + java.util.Arrays.toString(original));
        System.out.println("Clone:    " + java.util.Arrays.toString(clone));
    }
}
Run Code

Это работает, потому что массивы в Java по умолчанию реализуют интерфейс Cloneable, а значит, поддерживают метод clone(). Но есть одна загвоздка: для одномерных массивов примитивных типов метод clone() эффективно выполняет поверхностное копирование значений. Из-за того, что мы работаем с примитивами, не имеет значения, произошло поверхностное копирование или глубокое, потому что каждый элемент просто дублируется. Но как только мы переходим к многомерным массивам, все становится еще интереснее!

Копирование многомерных массивов

Когда мы вызываем clone() для многомерного массива, Java создает новый “внешний” массив, но не создает отдельные подмассивы для каждой ячейки. Вместо этого каждая ссылка на подмассив повторно используется из исходного массива. Происходит поверхностное копирование.

Если вы напишете что-то вроде:

public class MultiDimClone {
    public static void main(String[] args) {
        int[][] original = {
            {1, 2, 3},
            {4, 5, 6}
        };

        int[][] clone = original.clone();

        System.out.println("Original[0] == Clone[0]? " + (original[0] == clone[0]));
    }
}
Run Code

Строка (original[0] == clone[0]) выведет true, указывающее, что и исходный, и клонированный массив указывают на один и тот же подмассив для original[0]. Это означает, что изменение clone[0] или original[0] может повлиять на оба массива, поэтому будьте осторожны! Это поверхностная копия, а не глубокая копия всей структуры.

Если вам нужна глубокая копия многомерного массива, вам придется делать это вручную или с помощью библиотеки, которая поддерживает такую возможность, копируя каждый подмассив в новый массив. Это гарантирует, что изменения в копии не повлияют на оригинал.

Езё немного о методе clone()

Метод clone() возвращает объект, который необходимо привести к соответствующему типу (например, int[] или String[]). Именно это и происходит под капотом, когда вы выполняете int[] clone = original.clone(). Никакого специального кода не нужно!

Массивы в двух словах

  • Основные характеристики массива: тип данных, помещаемых в него, его имя и его длина. Длина определяется при создании массива, когда выделяется память. Имя и тип данных определяются при объявлении массива.
  • Количество ячеек должно быть целочисленным.
  • Изменить длину массива после его создания невозможно.
  • Доступ к элементу массива можно получить по его индексу.
  • Элементы массивов нумеруются с нуля.
  • При создании массив заполняется значениями по умолчанию.

Перевод статьи «Java Arrays».

Про многомерные массивы можно почитать тут: «Многомерные массивы»

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх