четверг, 31 мая 2012 г.

Массивы в языке Java, класс Arrays

Массивы являются элементом практически любой программы. Поэтому разработчики языка Java уделили этому вопросу достаточно много времени и проделали большую работу, что бы ими было пользоваться как можно удобней. В этой статье я рассмотрю, как самые известные способы работы, так и то, о чём часто даже не догадываются начинающие программисты, но что значительно упрощает программирование.

Для того чтобы начать работать с массивом какого либо типа нужно объявить переменную типа массив например для типа int это будет выглядеть так:
int[] numbers;
Или так:
int numbers[];
В особых случая можно даже так:
public static void main(String... args){
}
Но первый вариант более предпочтителен, так как в нём явно отделяются тип переменной от её имени и его можно использовать в любом месте кода, где можно объявить переменную. Именно этим вариантом я и буду пользоваться в дальнейшем. 
После этого необходимо выделить память под этот массив. Обычно это происходит вот так:
int[] numbers;
numbers = new int[10];
Можно объявлять переменную и инициализировать её в одной строке:
int[] numbers = new int[10];
Если же элементы будущего массива известны заранее, то можно использовать такой синтаксис:
int[] numbers = {23,43,22,34,14,56,86,77,810,9};
Что бы теперь обратиться к элементам этого массива, мы можем использовать индекс элемента от 0 до 9 (в Java элементы массива нумеруются от 0, поэтому верхняя граница на 1 меньше, чем при инициализации):
int[] numbers = new int[10];
int first = numbers[0];
number[4] = 76;
int last = numbers[9];
for(int i = 0; i < 10; i++){
  System.out.println(number[i]);
}
Рис 1. Ссылка на массив.
Рис 1. Ссылка на массив

При этом следует помнить, что в переменной хранится не весь массив, а только ссылка на этот массив. Это можно увидеть наглядо на рисунке 1. Казалось бы, как нам разница, хранится весь массив или только ссылка на него? В реальности же оказывается если не учитывать этого момента, то можно попасть в достаточно неприятную ситуацию. Рассмотрим простой пример:
int[] numbers = {1,23, 13};
int[] numbersCopy = numbers;
numbersCopy[1] = 43;

for(int i = 0; i < 3; i++){
  System.out.print(numbers[i]);
}
System.out.println();

for(int i = 0; i < 3; i++){
  System.out.print(numbersCopy[i]);
}
Рис 2. Копирование ссылки
Рис 2. Копирование ссылки

Если считать, что в переменных хранятся не ссылки а массивы целиком, то результат должен был бы быть вывод двух строк: "12313" и "14313", но в реальности мы получим две одинаковые строки: "14313". Это происходит из-за того, что мы переменной nubmersCopy присваеваем не копию массива, а копию ссылки. И у нас получаются две переменные с одинаковыми значениями, но значения эти не массивы, как мы хотели, а ссылки на массив. Графически это можно изобразить так, как на рисунке 2. Самый простой способ избежать этого, это использовать метод clone у любого объекта типа массив. Так же объект класса массив имеет константу, в которой хранится количество элементов массива — length. Таким образом код можно переписать следующим образом:
int[] numbers = {1,23, 13};
int[] numbersCopy = numbers.clone();
numbersCopy[1] = 43;

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

for(int i = 0; i < numbersCopy.length; i++){
  System.out.print(numbersCopy[i]);
}
Рис 3. Массив массивов
В языке Java не существует многомерных массивов, но тем не менее у нас есть возможность в элементе массива хранить другой массив, что позволяет имитировать многомерные массивы. Благодаря этому мы можем создавать многомерные массивы с произвольной длинной элементов. Это проиллюстрированно на рисунке 3. В коде это выглядит следующим образом:
/*Простой двумерный массив*/
int[][] twoDimensionsArray = new int[3][5];
/*Массив с разными размерностями, как на рис. 3*/
int[][] twoDimenstionsArray2 = {
  {2,4,223},
  {54,215},
  {25,64,26,67}
};
/*Массив с разными размерностями, как на рис. 3*/
int[][] twoDimenstionsArray3 = new int[3][];
differentDimensions[0] = new int[3];
differentDimensions[1] = new int[2];
differentDimensions[2] = new int[4];
При работе с такими массивами полезно знать один трюк: всегда старайтесь располагать массивы с наименьшем числом элементов ближе к правой стороне, например:
  int[][] twoDimensionsArray = new int[3][500][2000][10000];
Дело в том, что для хранения каждого массива JVM хранит дополнительную информацию, и расположив массивы подобным образом вы уменьшите количество необходимой дополнительной информации до минимума.

Класс java.util.Arrays

Класс Arrays предназначен для работы с массивами. Он содержит методы для работы с целыми массивами, например:
  •  copyOf — предназначен для копирования массива;
  • copyOfRange — копирует часть массива;
  • toString — позволяет получить все элементы в виде одной строки;
  • sort — сортирует массив методом quick sort; 
  • binarySearch — ищет элемент методом бинарного поиска; 
  • fill — заполняет массив переданным значением (удобно использовать, если нам необходимо значение по умалчанию для массива); 
  • equals — проверяет на идентичность массивы; 
  • deepEquals — проверяет на идентичность массивы массивов; 
  • asList — возвращает массив как коллекцию (коллекции будут рассмотрены в следующий раз).
Пример использования класса Arrays:
  int[] first = {31,25,3,324,22,33,643,12};
  int[] second;
  
  second = Arrays.copyOf(first, first.length);
  System.out.println(Arrays.equals(first, second));

  Arrays.sort(first);
  System.out.println(Arrays.equals(first, second)); 
  System.out.println(Arrays.toString(first));
  System.out.println(Arrays.toString(second));
  
  Arrays.fill(second, 100);
  System.out.println(Arrays.toString(second));
Если мы запустим этот код, то получим такой вывод:
true
false
[3, 12, 22, 25, 31, 33, 324, 643]
[31, 25, 3, 324, 22, 33, 643, 12]
[100, 100, 100, 100, 100, 100, 100, 100]

4 комментария:

  1. Добрый день! В фрагменте, что ниже, ничего не пропущено? Или вы хотите показать, что параметр args тоже массив?

    «В особых случая можно даже так:

    public static void main(String... args){

    ОтветитьУдалить
    Ответы
    1. Здравствуйте! Спасибо за комментарий. Нет, ничего не пропущено. Действительно просто хотел показать такую возможность.

      Удалить
  2. int[][] array = {{1,2,3}, {1,2,3}, {1,2,3}};
    int[][] array1 = {{1,2,3}, {1,2,3}, {1,2,3}};

    System.out.println(Arrays.deepEquals(array,array1));
    почему выдает false если массивы одинаковы?

    ОтветитьУдалить