Урок 5

Массивы

1. Что такое массивы?

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

Представим, что у вас есть приют для бездомных животных, в котором пять котов. Как зовут каждого вы не помните, но у каждого есть жетончик с номерком, который позволяет идентифицировать каждое животное. Можно сказать, что это и есть массив "котики" размером пять. Обратите внимание, на то что индексация начинается с нуля - так принято в Java. Если бы не было возможности создавать массивы, нужно было бы объявлять пять переменных и придумывать им имена, что не очень удобно. 

Массивы

В Java можно создавать массивы любой размерности - одномерные, двумерные, трехмерные и т.д. Начнем с простейшего варианта - с одномерных массивов.

2. Одномерные массивы

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

тип[] имяПеременной;

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

Пример 1. Пример объявления массивов

Квадратные скобки можно ставить перед переменной или после нее. Но более правильным вариантом считается указание скобок перед переменной - таким образом тип и скобки находятся в одном месте, что позволяет с первого взгляда понять, что перед вами массив такого-то типа.

int monthDays[];
double[] monthSalaries;

2.1. Инициализация массива с помощью ключевого слова new 

Когда массив объявлен, память под него еще не выделена. Для выделение памяти под массив используется ключевое слово new, после которого опять указывается тип массива и в квадратных скобках - размер:

имяПеременной = new тип[размер];

Массив может быть объявлен и инициализирован одной строкой:

int[] values = new int[45];

Пример 2. Пример объявления массива

Рассмотрим пример объявления массива типа int размером 12 на данном примере. После выполнения строки int[] monthDays = new int[12] массив из 12 элементов создан. Каждому элементу присваивается значение по умолчанию для заданного типа. Для типа int это ноль. Для обращения к отдельному элементу массива после имени массива в квадратных скобочках задаем индекс элемента. Таким образом мы можем обратиться к элементу массива для изменения или получения его значения. 

public class Array1 {
    public static void main(String[] args) {
        int[] monthDays = new int[12];
        monthDays[0] = 31;
        monthDays[1] = 28;
        monthDays[2] = 31;
        monthDays[3] = 30;
        monthDays[4] = 31;
        monthDays[5] = 30;
        monthDays[6] = 31;
        monthDays[7] = 31;
        monthDays[8] = 30;
        monthDays[9] = 31;
        monthDays[10] = 30;
        monthDays[11] = 31;
        System.out.println("B апреле " + monthDays[3] + " дней.");
    }
}

2.2. Инициализация массива с помощью блока для инициализации

Пример 3. Пример инициализации одномерного массива

Если заранее известны значения для каждого элемента массива, можно использовать блок для инициализации массива. Вместо new int[12], в фигурных скобках через запятую перечисляются значения элементов массива. Размер массива выводится компилятором из количества указанных элементов.

public class Array2 {
    public static void main(String[] args) {
        int[] monthDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        System.out.println("B апреле " + monthDays[3] + " дней.");
    }
}

2.3. Безымянный массив

Существует еще и третья форма объявления массива - безымянный массив. Он может использоваться в двух случаях. Первый - вы объявили и инициализировали массив testScores размера четыре, но потом по какой-то причине он должен быть изменен - он должен содержать три элемента. Использовать повторно форму для инициализации массива нельзя - будет ошибка компиляции:

int[] testScores = {1, 2, 3, 4};
...
testScores = {4, 7, 2}; //ошибка компиляции

Но можно использовать безымянный массив, который создаст новый массив в памяти. Форма написания безымянного массива - это микс первых двух:

testScores = new int[]{4, 7, 2};

Второй случай использования безымянного массива - это передача массива в метод. В следующем примере метод print принимает на входа массив типа int. При вызове метода в качестве аргумента можно передать безымянный массив.

Пример 4. Пример безымянного массива

public class Array3 {
    public static void main(String[] args) {
        int[] testScores = {1, 2, 3, 4};
        for (int element : testScores) {
            System.out.print(element + " ");
        }
        System.out.println();
        testScores = new int[]{4, 7, 2};
        for (int element : testScores) {
            System.out.print(element + " ");
        }
        System.out.println();

        print(new int[]{4, 6, 2, 3});
    }

    public static void print(int[] array) {
        for (int element : array) {
            System.out.print(element + " ");
        }
    }
}

3. Многомерные массивы

Многомерные массивы представляют собой массивы массивов.

При объявлении переменной многомерного массива для указания каждого дополнительного индекса используется отдельный ряд квадратных скобок. Например:

int[][] twoD = new int[4][5];

3.1. Концептуальное представление массива размерностью 4 на 5

Следующий рисунок показывает как можно визуально представить двумерный массив 4 на 5. Левый индекс определяет строку, а правый столбец.

Концептуальное представление массива размерностью 4 на 5

Пример 5. Пример двухмерного массива

Следующий пример демонстрирует каким образом можно установить значения в двухмерный массив 4x5. Для перебора строк используется внешний цикл for, для перебора столбцов - внутренний. Каждому следующему элементу присваивается значение на единицу большее чем предыдущее.

public class TwoDArray1 {
    public static void main(String[] args) {
        int[][] twoD = new int[4][5];
        int i, j, k = 0;
        for (i = 0; i < 4; i++) {
            for (j = 0; j < 5; j++) {
                twoD[i][j] = k++;
                System.out.print(twoD[i][j] + " ");
            }
            System.out.println();
        }
    }
}

3.2.Представление многомерного массива в памяти

Рассмотрим теперь как представлен массив int[][] twoD = new int[3][4]; в памяти.Переменная twoD указывает не на матрицу, а на строку (красного цвета)  состоящую из трех элементов. Значение каждого элемента - это ссылка на строку из четырех элементов (фиолетового цвета).

Представление двухмерного массива в памяти

Следующая картинка показывает каким образом хранится трехмерный массив int[][][] threeD = new int[3][4][2] в памяти:

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

Подобным образом может храниться массив любой размерности в памяти.

3.3. Пример двухмерного массива c разной размерностью

В двухмерных массивах, которые мы рассматривали до сих пор, количество элементов в каждой строке одинаково - чаще всего так и бывает. Но это не обязательно, каждая строка может содержать разное количество элементов. Например:

Пример двухмерного массива c разной размерностью

Пример 6. Пример двухмерного массива с разной размерностью

Посмотрим код, реализующий такой массив. При объявлении массива необходимо задать количество элементов только для первой размерности - int[][] array = new int[4][]. Таким образом, мы указываем количество строк в массиве, но под каждую строку память не выделяем. Далее выделяем отдельно память под каждую строку массива. Например, строка с индексом ноль будет размера 1 - array[0] = new int[1]. 

public class TwoDArray2 {
    public static void main(String[] args) {
        int[][] array = new int[4][];
        array[0] = new int[1];
        array[1] = new int[2];
        array[2] = new int[3];
        array[3] = new int[4];
        int i, j, k = 0;
        for (i = 0; i < 4; i++) {
            for (j = 0; j < i + 1; j++) {
                array[i][j] = k++;
                System.out.print(array[i][j] + " ");
            }
            System.out.println();
        }
    }
}

3.4. Блок для инициализации многомерного массива

Пример 7. Инициализация двухмерного массива

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

public class TwoDArray3 {
    public static void main(String[] args) {
        double[][] arrayTwoD = {
                {0, 1, 2, 3},
                {4, 5, 6, 7},
                {8, 9, 10, 11},
                {12, 13, 14, 15}
        };
        for (double[] arrayOneD : arrayTwoD) {
            for (double element : arrayOneD) {
                System.out.print(element + " ");
            }
            System.out.println();
        }
    }
}

3.4. Длина массива

Пример 8. Получение длины массива

Следующий пример демонстрирует как получать длину массива. Для этого используется переменная length. С одномерным массивом все понятно - его длина это количество его элементов. Длина многомерного массива - это количество элементов его первой размерности. Например, длина массива array2 - это 2. Также можно получить длину каждой строки массива. Например, array2[0].length - вернет количество элементов в строке с индексом ноль.

public class ArraySize {
    public static void main(String[] args) {
        int[] array1 = {1, 2, 3, 4};
        int[][] array2 = {{1, 1, 1}, {2, 2, 2}};
        System.out.println("Размер массива array1 = " + array1.length);
        System.out.println("Размер массива array2 = " + array2.length);
        System.out.println("Размер 1-строки массива array2 = "
                + array2[0].length);
    }
}

Результат выполнения:

Размер массива array1 = 4
Размер массива array2 = 2
Размер 1-строки массива array2 = 3

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

Существует ряд методов, полезных при работе с массивами. Рассмотрим их:

4.1. Метод Arrays.toString()

Метод возвращает строковое представление одномерного массива, разделяя элементы запятой. Вместо того, чтобы перебирать массивы циклом for, как мы делали в примере 4, можно воспользоваться этим методом для вывода элементов на консоль:

Пример 9. Применение метода Arrays.toString()

import java.util.Arrays;

public class ArraysToStringDemo {
    public static void main(String[] args) {
        int[] array = {1, 4, 6, 3, 8};
        System.out.println(Arrays.toString(array));
    }
}

4.2. Метод Arrays.deepToString()

Метод возвращает строковое представление многомерного массива, выделяя строки квадратными скобками:

Пример 10. Применение метода Arrays.deepToString()

import java.util.Arrays;

public class ArraysDeepToStringDemo {
    public static void main(String[] args) {
        String[][] array = {{"один-один", "один-два", "один-три"},
                {"два-один", "два-два", "два-три"}};
        System.out.println(Arrays.deepToString(array));
    }
}

4.3. Метод Arrays.sort()

Метод Arrays.sort() сортирует элементы числового массива по возрастанию:

Пример 11. Сортировка массива

import java.util.Arrays;

public class ArraysSort1 {
    public static void main(String[] args) {
        int[] array = new int[]{3, 1, 5, 6, 8};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
    }
}

4.4. Метод Arrays.binarySearch()

Метод Arrays.binarySearch() ищет в массиве заданное значение и возвращает номер элемента. Если искомый элемент не найден, то возвращается -(position + 1), где position - позиция элемента где он МОГ БЫ БЫТЬ. Массив должен быть отсортирован, иначе результат вызова метода будет неопределен:

Пример 12. Поиск элемента массива

import java.util.Arrays;

public class BinarySearch1 {
    public static void main(String[] args) {
        int[] array1 = {10, 20, 30, 40};
        int pos1 = Arrays.binarySearch(array1, 20);
        int pos2 = Arrays.binarySearch(array1, 25);
        System.out.println(pos1);
        System.out.println(pos2);
    }
}

Результат выполнения:

1
-3

4.5. Метод System.arraycopy()

Метод System.arraycopy() позволяет копировать часть массива в другой массив.

Пример 13. Копирование массива

Рассмотрим пример, копирующий элементы 2,3,4 из массива arraySource в массив arrayDestination:

import java.util.Arrays;

public class ArrayCopy1 {
    public static void main(String[] args) {
        int[] arraySource = {1, 2, 3, 4, 5, 6};
        int[] arrayDestination = {0, 0, 0, 0, 0, 0, 0, 0};

        System.out.println("arraySource: " + Arrays.toString(arraySource));
        System.out.println("arrayDestination: "
                + Arrays.toString(arrayDestination));

        System.arraycopy(arraySource, 1, arrayDestination, 2, 3);
        System.out.println("arrayDestination after arrayCopy: "
                + Arrays.toString(arrayDestination));
    }
}

Результат выполнения:

arraySource: [1, 2, 3, 4, 5, 6]
arrayDestination: [0, 0, 0, 0, 0, 0, 0, 0]
arrayDestination after arrayCopy: [0, 0, 2, 3, 4, 0, 0, 0]

Пример 14. Копирование массива из себя в себя

Можно копировать в тот же массив с перекрытием областей:

import java.util.Arrays;

public class ArrayCopy2 {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6, 7, 8};
        System.out.println(Arrays.toString(array));

        System.arraycopy(array, 1, array, 3, 3);
        System.out.println(Arrays.toString(array));
    }
}

Результат выполнения:

[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 2, 3, 4, 7, 8]



0 Comments
Leave your comment: