Рубріки: ОсновиТеорія

Масиви в Java: що це таке і як з ними працювати

Сергій Бондаренко

Що таке масив?

У програмуванні часто працюють із такою математичною структурою як масив. У мові Java він сприймається як група елементів одного типу. 

Масив — це структура фіксованого розміру, її не можна динамічно змінювати, як, наприклад, реалізовано в колекціях Java. У масивів є маса застосувань — від аналізу статистичних даних та аналізу їхньої структури до матричних обчислень та векторних операцій. 

Оскільки масив Java є об’єктом, для його створення використовується звичний спосіб: задається змінна (під ім’ям якої ми маємо на увазі сам масив, хоча насправді вона зберігає лише посилання на нього), а потім за допомогою оператора new описуємо структуру масиву. 

Важлива характеристика масиву — його розмірність.

Розмірність — це кількість індексів, необхідних для звернення до елемента масиву. Доступ до будь-якого компоненту масиву здійснюється за допомогою ідентифікатора, який називається індексом елемента.

У цьому слід пам’ятати: нумерація елементів масиву починається з нуля. Найчастіше задіяні одномірні масиви, масиви ж кратністю більше двох використовуються практично дуже рідко. 

Важливо: у Java-масиві не можна змішувати типи полів.

Оголошення масиву

Команда для оголошення масиву виглядає так:

типелементів[] ім'я_змінної;

або так:

типелементів ім'я_змінної[];

Обидва записи — рівнозначні. 

Процес генерування масиву та запис посилання на нього в змінну виглядає так:

типелементів[] змінна;

змінна=new тип елементів [розмір масиву];

Для обох команд допускається більш коротка форма:

тип елементів[] змінна=new типелементів[розмір_масиву];

Розглянемо загальні форми оголошення одномірного масиву.

Оголошення масиву Приклад Коментар
type variable_name [] int anArray [] Java-стиль
type [] variable_name int [] anArray Стиль, що перекочував у Java з мови програмування С

При використанні такого оголошення ми маємо знати, що фактичного масиву поки що не існує. Тут ми просто відправляємо повідомлення компілятору, про те, що поле anArray колись буде пристосовано під масив із цілими числами. Щоб пов’язати anArray з реальним цілим масивом, потрібно оголосити його за допомогою ключового слова new:

int[] anArray = new int[10];

У прикладі числове значення у квадратних дужках показує кількість слотів під елементи масиву. У нашому випадку ми виділяємо під масив десять осередків пам’яті.

Наприклад:

int [] anArray; // оголошення масиву
anArray = new int [20]; // виділяємо пам'ять для масиву

Або:

int [] intArray = new int [20]; // об'єднуємо оголошення з виділенням пам'яті

Примітка: осередкам у масиві, як виділені за допомогою ключового слова new, будуть автоматично присвоєні значення: 0 (для числового типу), false (для логічного) та null (для посилань).

Створення масиву

Припустимо, ми хочемо створити масив цілих чисел на 13 елементів. Надамо групі елементів ім’я — highloadToday:

int[] highloadToday = new int[13];

Виведемо на екран довжину масиву:

System.out.println(highloadToday.length);

У консолі відобразиться 13.

Аналогічно створюються набори інших типів. Наприклад, ця команда оголошує масив з десятьма змінними типу double і надає посилання firstList:

double[] firstList = new double[10];

Як дізнатися довжину масиву

Ми з вами розібралися, що довжиною масиву є кількість осередків, виділена для зберігання даних, і цю довжину неможливо буде змінити, коли масив вже створено. У Java рахунок елементів по порядку в масиві починається не з одиниці, а з нуля.

Як дізнатися довжину масиву

Щоб дізнатися довжину нашого масиву, використовуємо його властивість length. Наприклад:

int[] anArray = new int[10]; // створюємо цілочислений масив на 10 осередків і присвоюємо йому ім'я anArray
System.out.println(anArray.length); // виводимо довжину нашого масиву

Ініціалізуємо масив, працюємо з його елементами

Тепер ми знаємо, що таке масив, але як його використовувати поки що незрозуміло. Як завантажувати інформацію, а потім її звідти витягувати? Давайте розбиратися.

У широкому значенні масив — це найважливіша структура даних у програмуванні. Сам комп’ютер — це не що інше, як набір масивів. Байт — це масив із восьми двійкових розрядів, а рядок — це масив символів.

Розробники використовують масиви, тому що вони працюють швидко і дозволяють безпосередньо звертатися до даних окремого елемента за комп’ютерний цикл незалежно від розміру масиву.

Через операційну систему, віртуальну пам’ять та інші фактори для вилучення елемента з масиву може знадобитися трохи більше, ніж один фактичний комп’ютерний цикл. Але час вилучення першого елемента такий самий, як і 100-го елемента і 500-тисячного. Жодна інша створена нами структура даних не може бути швидшою за масив. Усі «просунуті» системи реалізовані з їх використанням.

Тепер давайте з’ясуємо особливості роботи із цією корисною штукою. При оголошенні створюється масив у кожному осередку якого дані за замовчуванням (це ми розібрали). Щоб записати туди необхідні нам дані, потрібно провести обряд ініціалізації, тобто надати кожному осередку певне значення.

Наприклад, створимо масив, що містить у собі чотири сторони світу, і заповнимо його значеннями:

String[] sides  = new String[4]; /* оголошеному масиву Java виділив пам'ять для чотирьох рядків (за замовчуванням їх значення буде null, тому що String відноситься до типу посилань)*/sides[0] = "North"; /* Отримавши доступ до першого осередку (з нульовим індексом), ми вписали туди рядкове значення */sides[1] = "South"; // теж саме ми робимо з осередком під індексом 1
sides[2] = "West"; // 2
sides[3] = "East"; // 3

Ми використовуємо індекси для доступу до осередків масиву, число в дужках позначає кожну конкретну позицію. Якщо переданий при доступі до осередка індекс — негативний або перевищує довжину масиву, Java видасть виняток ArrayIndexOutOfBoundException.

Тепер поєднаємо ініціалізацію з оголошенням:

String[] sides = new String[] {"North", "South", "West", "East"};

І приберемо оператор new, тим самим спростивши запис:

String[] sides = {"North", "South", "West", "East"};

Виводимо масив у консоль

Є кілька способів перебору масивів, один з них циклічний, наприклад, за допомогою циклу for:

String[] sides = new String[] {"North", "South", "West", "East"};
for (int i = 0; i < 4; i++) {
    System.out.println(sides[i]);
}

Виведе:

North
South
West
East

Багатовимірні Java-масиви

Масиви, у яких лише один індекс називається одновимірним, ми вже розглянули. Але в них можна поміщати не лише примітивні типи даних та посилання на об’єкти, а й інші масиви. У такому разі їх називають багатовимірними.

Давайте на прикладі з’ясуємо, що вони собою являють. Припустимо, нам потрібен масив для зберігання кількості вільних місць у кінотеатрі. Ось візуальне уявлення про те, про що я кажу:

Структура багатовимірного масиву Java (тут ми бачимо вільні місця в кінотеатрі)

Звичайно в реальному житті кінотеатр був би більшим, але цей нам якраз підійде як приклад.

0 означає, що місце доступне, 1 — що зайняте. Ми також могли б додати ще й 2 для зарезервованих місць тощо. Але поки що обмежимося більш простим прикладом.

Java не надає жодної спеціальної підтримки для багатовимірних масивів, але ми можемо легко оголосити їх як масив масивів. Це буде виглядати так:

int [] [] cinema = новий int [5] [5];

Перше число вказує кількість стовпців, друге кількість рядків. Усі числові масиви Java автоматично ініціалізуються нульовими значеннями після оголошення. Ми щойно створили таблицю, повну нулів.

Тепер давайте заповнимо кінозал одиницями, як на зображенні вище. Для створення рядка з одиниць використовуємо кілька циклів for. Щоб відкрити доступ до елементів 2D-масиву, ми повинні ввести координати стовпців та рядків:

cinema[2][2] = 1; // центр
for (int i = 1; i < 4; i++) { // четвертий рядок
    cinema[i][3] = 1;
}
for (int i = 0; i < 5; i++) { // останній рядок
    cinema[i][4] = 1;
}

Потрібно мати на увазі, що якщо ми запитаємо cinema.length, він міститиме кількість стовпців (довжину зовнішнього масиву, що представляє стовпці). Щоб визначити кількість рядків (довжину внутрішнього масиву) необхідно запросити cinema [0].length. Зверніть увагу, що для роботи має бути хоча б один стовпець.

Ми вкладатимемо цикли по порядку, щоб зовнішній цикл проходив рядками, а внутрішній — стовпцями поточного рядка. Після виведення рядка в консоль ми повинні розірвати її, адже обидва цикли повинні мати різні змінні, що управляють:

for (int j = 0; j < cinema[0].length; j++) {
    for (int i = 0; i < cinema.length; i++) {
        System.out.print(cinema[i][j]);
}
    System.out.println();
}

Результат:

00000
00000
00100
01110
11111

Іноді корисно створити масив з великою кількістю вимірювань. Наприклад, тривимірний. Повернемося до прикладу з кінотеатром. Тепер уявімо, що в ньому кілька поверхів. Схематично це виглядатиме так:

3D-масив

Давайте створимо 3D-масив:

int [] [] [] cinemas = новий int [5] [5] [3];

Доступ до елементів наведеного вище тривимірного масиву ми можемо отримати, як і раніше, через індекс, але тепер нам потрібно ввести три координати:

cinemas[3][2][1] = 1; // кінотеатр на другому поверсі, третій ряд, четверте місце

У такій ситуації, якщо ми запитаємо cinemas[0][0].length, то отримаємо кількість поверхів.

Робота з масивами

Продемонструємо найпростіші маніпуляції з елементами масиву:

public class Array
{
    public static void main(String[] args) {

        int[] a = new int[4];
        a[0] = 17; //Ініціалізація елементів масиву
        a[1] = 15;
        a[2] = 8;
        a[3] = 8;
 
        String[] s = {"October", "November", "December"}; /* Ініціалізацію та оголошення можна застосовувати паралельно*/        String[] s2 = new String[]{"Highload", "Today"}; /*Іноді ініціалізація та оголошення можуть застосовуватись разом з оператором new */        s2[0] = "Highload - "; //Змінюємо перший елемент масиву
        System.out.println(s2[0] + s2[1]); // Відображення в консолі "Highload - Today"
        a[2] = 5; // Компоненти масиву - змінні
        System.out.println(a[2]);
    }
}

Пошук у масиві за елементом

Операція з масивами, які зустрічаються найчастіше, — пошук за елементом. Є багато алгоритмів, що дозволяють її вирішити. Наприклад, можна обрати найбільш легкий, але і найповільніший метод пошуку — лінійний:

 public static int linearSearch(int[] array, int elementWanted) {
    for (int i = 0; i < array.length; i++) {
        if (array[i] == elementWanted) {
            return i;
        }
    }
    return -1;
}

Якщо наш масив вже впорядкований, можемо застосувати інший спосіб.

Для пошуку:

  • ми поділяємо масив на рівні частини;
  • дивимося на «центральний елемент» з індексом middleIndex;
  • порівнюємо з розшукуваним елементом;
  • якщо є збіг — алгоритм завершуємо.

Коли розшукуваний елемент менше за «центральний елемент» ми забуваємо про праву частину масиву, а інакше — про ліву частину. Потім повторюємо ці дії до виявлення елемента або поки що черговий відрізок не стане порожнім. Якщо елемент не виявлено, повертається значення -1:

public static int binarySearch(int[] array, int elementWanted) {
        int firstIndex = 0;
        int lastIndex = array.length - 1;

        // умова припинення (елемент не представлений)
        while (firstIndex <= lastIndex) {
            int middleIndex = (firstIndex + lastIndex) / 2;
            // умова припинення (елемент не представлений)
            if (array[middleIndex] == elementWanted) {
                return middleIndex;
            }

            // коли центральний елемент у масиві менший
            // переводимо індекс у middle+1, не розглядаючи першу частину

            else if (array[middleIndex] < elementWanted) {
                firstIndex = middleIndex + 1;
            }
            // якщо центральний елемент більший
            // переводимо наш індекс у middle-1, не розглядаючи першу частину 

            else if (array[middleIndex] > elementWanted) {
                lastIndex = middleIndex - 1;
            }
        }
        return -1;
    }

Сортування масивів

Виконувати впорядкування масиву можна за допомогою методу .sort() класу Arrays (не забуваємо на початку програми додавати import java.util.Arrays;):

int[] highload = { 24, 7, 23, 6765, 95, 33 };
Arrays.sort(highload);
System.out.println(Arrays.toString(highload));// [7, 23, 24, 33, 95, 6765]

Більш детально про різні алгоритми сортування масивів можете почитати у статті «Методи сортування та їх реалізація в Python». Незважаючи на те, що ми писали в цій статті про Python, всі алгоритми є актуальними і для Java. 

Перетворення масиву на рядок

Іноді може виникнути необхідність перетворення масиву на рядок. Існують різні способи вирішення цього завдання. Наприклад, звернутися до статичного методу join() класу String, який поєднує елементи масиву. У цьому прикладі елементи масиву відокремлюються за допомогою вказаним параметром — розділювачем:

String[] words = ["Highload", "Today"];

// Розділювач може бути порожнім рядком
String.join("", words); // "HighloadToday"
String.join(", ", words); // "Highload, Today"

Java.util.Arrays: готові рішення для обробки масивів

Операції по роботі з java-масивами, що найчастіше використовуються:

  • сортування;
  • пошук необхідного елемента;
  • перетворення масиву на рядок.

Одним із найзручніших способів вирішення такого роду завдань є використання класу Arrays пакету java.util. Розглянемо з прикладу їх реалізацію:

class Main {
    public static void main(String[] args) {
        int[] test = {1, 5, 4, 3, 7}; //оголошення та ініціалізація масиву
        System.out.println(test); //спроба виведення нашого масиву в консоль (результат 16-річне число)
        System.out.println(Arrays.toString(test)); //виводимо в консоль масив за допомогою методу toString і тішимося вірному результату
        Arrays.sort(test, 0, 4); //сортування масиву від 0-го до 4-го осередку
        System.out.println(Arrays.toString(test)); //виводимо результат сортування
        int keyArray = Arrays.binarySearch(test, 8); // пошук keyArray - тобто числа 8 у відсортованому масиві, метод binarySearch видає індекс шуканого елемента
        System.out.println(keyArray); //виводимо в консоль цей індекс
System.out.println(Arrays.binarySearch(test, 0)); //пробуємо знайти елемент, відсутній у масиві та виводимо результат у консоль
    }
}

Виведе:

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

Висновок

  • Масив — це об’єкт-контейнер, що містить у собі встановлену при створенні кількість значень певного типу, яка не може бути змінена.
  • Нумерація елементів масиву починається із нуля.
  • Доступ до осередків масиву легко отримати за його індексом.
  • Найбільш зручні інструменти для обробки масивів надає клас Java.util.Arrays.

Тепер ви можете самостійно керувати таким важливим математичним інструментом у мові Java. Якщо ви бажаєте закріпити отримані знання, рекомендуємо вам переглянути відео, в якому детально розібрано ряд завдань, пов’язаних з одновимірними та багатовимірними масивами Java:

 

Останні статті

Айтівець Міноборони США понабирав кредитів і хотів продати рф секретну інформацію

32-річний розробник безпеки інформаційних систем Агентства національної безпеки Джарех Себастьян Далке отримав 22 роки в'язниці…

30.04.2024

Простий та дешевий. Українська Flytech запустила масове виробництво розвідувальних БПЛА ARES

Українська компанія Flytech представила розвідувальний безпілотний літальний апарат ARES. Основні його переваги — недорога ціна…

30.04.2024

Запрошуємо взяти участь у премії TechComms Award. Розкажіть про свій потужний PR-проєкт у сфері IT

MC.today разом з Асоціацією IT Ukraine і сервісом моніторингу та аналітики згадок у ЗМІ та…

30.04.2024

«Йдеться про потенціал мобілізації»: Україна не планує примусово повертати українців із ЄС

Україна не буде примусово повертати чоловіків призовного віку з-за кордону. Про це повідомила у Брюсселі…

30.04.2024

В ЗСУ з’явився жіночий підрозділ БПЛА — і вже можна проходити конкурсний відбір

В Збройних Силах України з'явився жіночий підрозділ з БПЛА. І вже проводиться конкурсний відбір до…

30.04.2024

GitHub на наступному тижні випустить Copilot Workplace — ШІ-помічника для розробників

GitHub анонсував Copilot Workspace, середовище розробки з використанням «агентів на базі Copilot». За задумкою, вони…

30.04.2024