Java работа с двумерными массивами. Массивы в Java — определение и создание, инициализация и заполнение

Представьте себе ячейки в камере хранения. Каждая из них имеет свой номер, и в каждой из них хранится какой-то объект “Багаж”. Или винная карта, в которой все виды вина пронумерованы и когда вы делаете заказ, вам достаточно назвать номер напитка. Или список студентов группы, в котором в первой ячейке будет записан студент “Андреев”, а в последней - “Яковлев”. Или список пассажиров самолёта, за каждым из которых закреплено место с определённым номером. В Java чтобы работать с подобными структурами, то есть множеством однородных данных, часто используют массивы.

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

Массив - это структура данных, в которой хранятся элементы одного типа. Его можно представить, как набор пронумерованных ячеек, в каждую из которых можно поместить какие-то данные (один элемент данных в одну ячейку). Доступ к конкретной ячейке осуществляется через её номер. Номер элемента в массиве также называют индексом . В случае с Java массив однороден , то есть во всех его ячейках будут храниться элементы одного типа. Так, массив целых чисел содержит только целые числа (например, типа int), массив строк - только строки, массив из элементов созданного нами класса Dog будет содержать только объекты Dog . То есть в Java мы не можем поместить в первую ячейку массива целое число, во вторую String , а в третью - “собаку”.

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

Как объявить массив?

Как и любую переменную, массив в Java нужно объявить. Сделать это можно одним из двух способов. Они равноправны, но первый из них лучше соответствует стилю Java. Второй же - наследие языка Си (многие Си-программисты переходили на Java, и для их удобства был оставлен и альтернативный способ). В таблице приведены оба способа объявления массива в Java: В обоих случаях dataType - тип переменных в массиве. В примерах мы объявили два массива. В одном будут храниться целые числа типа int , в другом - объекты типа Object . Таким образом при объявлении массива у него появляется имя и тип (тип переменных массива). ArrayName - это имя массива.

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

Как создать массив?

Как и любой другой объект, создать массив Java, то есть зарезервировать под него место в памяти, можно с помощью оператора new . Делается это так: new typeOfArray [ length] ; Где typeOfArray - это тип массива, а length - его длина (то есть, количество ячеек), выраженная в целых числах (int). Однако здесь мы только выделили память под массив, но не связали созданный массив ни с какой объявленной ранее переменной. Обычно массив сначала объявляют, а потом создают, например: int myArray; // объявление массива myArray = new int [ 10 ] ; // создание, то есть, выделение памяти для массива на 10 элементов типа int Здесь мы объявили массив целых чисел по имени myArray , а затем сообщили, что он состоит из 10 ячеек (в каждой из которых будет храниться какое-то целое число). Однако гораздо чаще массив создают сразу после объявления с помощью такого сокращённого синтаксиса: int myArray = new int [ 10 ] ; // объявление и выделение памяти “в одном флаконе” Обратите внимание: После создания массива с помощью new , в его ячейках записаны значения по умолчанию. Для численных типов (как в нашем примере) это будет 0, для boolean - false , для ссылочных типов - null . Таким образом после операции int myArray = new int [ 10 ] ; мы получаем массив из десяти целых чисел, и, пока это не измениться в ходе программы, в каждой ячейке записан 0.

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

Как мы уже говорили выше, длина массива - это количество элементов, под которое рассчитан массив. Длину массива нельзя изменить после его создания. Обратите внимание: в Java элементы массива нумеруются с нуля. То есть, если у нас есть массив на 10 элементов, то первый элемент массива будет иметь индекс 0, а последний - 9. Получить доступ к длине массива можно с помощью переменной length . Пример: int myArray = new int [ 10 ] ; // создали массив целых чисел на 10 элементов и присвоили ему имя myArray System. out. println (myArray. length) ; // вывели в консоль длину массива, то есть количество элементов, которые мы можем поместить в массив Вывод программы: 10

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

Как создать массив в Java уже понятно. После этой процедуры мы получаем не пустой массив, а массив, заполненный значениями по умолчанию. Например, в случае int это будут 0, а если у нас массив с данными ссылочного типа, то по умолчанию в каждой ячейке записаны null . Получаем доступ к элементу массива (то есть записываем в него значение или выводим его на экран или проделываем с ним какую-либо операцию) мы по его индексу. Инициализация массива - это заполнение его конкретными данными (не по умолчанию). Пример: давайте создадим массив из 4 пор года и заполним его строковыми значениями - названиями этих пор года. String seasons = new String [ 4 ] ; /* объявили и создали массив. Java выделила память под массив из 4 строк, и сейчас в каждой ячейке записано значение null (поскольку строка - ссылочный тип)*/ seasons[ 0 ] = "Winter" ; /* в первую ячейку, то есть, в ячейку с нулевым номером мы записали строку Winter. Тут мы получаем доступ к нулевому элементу массива и записываем туда конкретное значение */ seasons[ 1 ] = "Spring" ; // проделываем ту же процедуру с ячейкой номер 1 (второй) seasons[ 2 ] = "Summer" ; // ...номер 2 seasons[ 3 ] = "Autumn" ; // и с последней, номер 3 Теперь во всех четырёх ячейках нашего массива записаны названия пор года. Инициализацию также можно провести по-другому, совместив с инициализацией и объявлением: String seasons = new String { "Winter" , "Spring" , "Summer" , "Autumn" } ; Более того, оператор new можно опустить: String seasons = { "Winter" , "Spring" , "Summer" , "Autumn" } ;

Как вывести массив в Java на экран?

Вывести элементы массива на экран (то есть, в консоль) можно, например, с помощью цикла for . Ещё один, более короткий способ вывода массива на экран будет рассмотрен в пункте “ . А пока рассмотрим пример с циклическим выводом массива: String seasons = new String { "Winter" , "Spring" , "Summer" , "Autumn" } ; for (int i = 0 ; i < 4 ; i++ ) { System. out. println (seasons[ i] ) ; } В результате программа выведет следующий результат: Winter Spring Summer Autumn

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

А что, если мы захотим создать не массив чисел, массив строк или массив каких-то объектов, а массив массивов? Java позволяет это сделать. Уже привычный нам массив int myArray = new int - так называемый одномерный массив. А массив массивов называется двумерным. Он похож на таблицу, у которой есть номер строки и номер столбца. Или, если вы учили начала линейной алгебры, - на матрицу. Для чего нужны нужны такие массивы? В частности, для программирования тех же матриц и таблиц, а также объектов, напоминающих их по структуре. Например, игровое поле для шахмат можно задать массивом 8х8. Многомерный массив объявляется и создается следующим образом: Int myTwoDimentionalArray = new int [ 8 ] [ 8 ] ; В этом массиве ровно 64 элемента: myTwoDimentionalArray , myTwoDimentionalArray , myTwoDimentionalArray , myTwoDimentionalArray и так далее вплоть до myTwoDimentionalArray . Так что если мы с его помощью представим шахматную доску, то клетку А1 будет представлять myTwoDimentionalArray , а E2 - myTwoDimentionalArray . Где два, там и три. В Java можно задать массив массивов… массив массивов массивов и так далее. Правда, трёхмерные и более массивы используются очень редко. Тем не менее, с помощью трёхмерного массива можно запрограммировать, например, кубик Рубика.

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

Для работы с массивами в Java есть класс java.util.Arrays (arrays на английском и означает “массивы”). В целом с массивами чаще всего проделывают следующие операции: заполнение элементами (инициализация), извлечение элемента (по номеру), сортировка и поиск. Поиск и сортировка массивов - тема отдельная. С одной стороны очень полезно потренироваться и написать несколько алгоритмов поиска и сортировки самостоятельно. С другой стороны, все лучшие способы уже написаны и включены в библиотеки Java, и ими можно законно пользоваться.

Статьи на поиск и сортировку:

Сортировка и поиск в курсе CS50:

Вот три полезных метода этого класса

Сортировка массива

Метод void sort(int myArray, int fromIndex, int toIndex) сортирует массив целых чисел или его подмассив по возрастанию.

Поиск в массиве нужного элемента

int binarySearch(int myArray, int fromIndex, int toIndex, int key) . Этот метод ищет элемент key в уже отсортированном массиве myArray или подмассиве, начиная с fromIndex и до toIndex . Если элемент не найден, возвращает номер элемента или fromIndex-1 .

Преобразование массива к строке

Метод String toString(int myArray) преобразовывает массив к строке. Дело в том, что в Java массивы не переопределяют toString() . Это значит, что если вы попытаетесь вывести целый массив (а не по элементам, как в пункте “ ”) на экран непосредственно (System.out.println(myArray)), вы получите имя класса и шестнадцатеричный хэш-код массива (это определено определено Object.toString()). Если вы - новичок, вам, возможно, непонятно пояснение к методу toString . На первом этапе это и не нужно, зато с помощью этого метода упрощается вывод массива. Java позволяет легко выводить массив на экран без использования цикла. Об этом - в примере ниже.

Пример на sort, binarySearch и toString

Давайте создадим массив целых чисел, выведем его на экран с помощью toString , отсортируем с помощью метода sort и найдём в нём какое-то число. class Main { public static void main (String args) { int array = { 1 , 5 , 4 , 3 , 7 } ; //объявляем и инициализируем массив System. out. println (array) ; //пытаемся вывести наш массив на экран без метода toString - получаем 16-ричное число //печатаем массив "правильно" Arrays. sort (array, 0 , 4 ) ; //сортируем весь массив от нулевого до четвёртого члена System. out. println (Arrays. toString (array) ) ; //выводим отсортированный массив на экран int key = Arrays. binarySearch (array, 5 ) ; // ищем key - число 5 в отсортированном массиве. //метод binarySearch выдаст индекс элемента остортированного массива, в котором "спрятано" искомое число System. out. println (key) ; //распечатываем индекс искомого числа System. out. println (Arrays. binarySearch (array, 0 ) ) ; //а теперь попробуем найти число, которого в массиве нет, // и сразу же выведем результат на экран } } Вывод программы: 3 -1 В первой строке - попытка вывода на экран массива без toString , во второй - вывод массива посредством toString , в третьей выведен отсортированный массив, в четвёртой - индекс искомого числа 5 в отсортированном массиве (помните, что считаем с нуля, поэтому четвёртый элемент массива имеет индекс 3). В пятой строке видем -1. Такого индекса у массива не бывает. Вывод сигнализирует о том, что искомого элемента (в данном случае, 0) в массиве нет.

Главное о массивах

    Главные характеристики массива: тип помещённых в него данных, имя и длина.
    Последнее решается при инициализации (выделении памяти под массив), первые два параметра определяются при объявлении массива.

    Размер массива (количество ячеек) нужно определять в int

    Изменить длину массива после его создания нельзя.

    Доступ к элементу массива можно получить по его индексу.

    В массивах, как и везде в Java, элементы нумеруются с нуля.

    После процедуры создания массива он наполнен значениями по умолчанию.

    Массив в языке Java значительно отличается от массива в языке C++. Однако он практически совпадает с указателем на динамический массив.

Полезные материалы о массивах

Хотите знать больше о массивах? Обратите внимание на статьи ниже. Там много интересного и полезного по этой теме.

    Кое-что о массивах - хорошая подробная статья о массивах

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

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

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

  • Tutorial

Думаю, мало кто из готовящихся к своему первому интервью, при приеме на первую работу в должности (pre)junior программиста, ответит на этот вопрос отрицательно. Или хотя бы усомнится в положительном ответе. Конечно, такая простая структура данных с прямым доступом по индексу - никаких подвохов! Нет, в некоторых языках типа JavaScript или PHP массивы, конечно, реализованы очень интересно и по сути являются много большим чем просто массив. Но речь не об этом, а о «традиционной» реализации массивов в виде «сплошного участка памяти». В этом случае на основании индексов и размера одного элемента просто вычисляется адрес и осуществляется доступ к соответствующему значению. Что тут сложного?
Давайте разберемся. Например, на Java. Просим ничего не подозревающего претендента создать массив целых чисел n x n . Человек уверено пишет что-то в духе:
int g = new int[n][n];
Отлично. Теперь просим инициализировать элементы массива чем-нибудь. Хоть единицами, хоть суммой индексов. Получаем:
for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { g[i][j] = i + j; } }
Даже чаще пишут
for(int i = 0; i < g.length; i++) { for(int j = 0; j < g[i].length; j++) { g[i][j] = i + j; } }
что тоже повод для беседы, но сейчас речь о другом. Мы ведь пытаемся выяснить, что человек знает и посмотреть, как он думает. По этому обращаем его внимание на тот факт, что значения расположены симметрично и просим сэкономить на итерациях циклов. Конечно, зачем пробегать все значения индексов, когда можно пройти только нижний треугольник? Испытуемый обычно легко соглашается и мудро выделяя главную диагональ старательно пишет что-то в духе:
for(int i = 0; i < n; i++) { g[i][i] = 2* i; for(int j = 0; j < i; j++) { g[j][i] = g[i][j] = i + j; } }
Вместо g[i][i] = 2* i; часто пишут g[i][i] = i + i; или g[i][i] = i << 1; и это тоже повод поговорить. Но мы идем дальше и задаем ключевой вопрос: На сколько быстрее станет работать программа? . Обычные рассуждения такие: почти в 2 раза меньше вычислений индексов; почти в 2 раза меньше вычислений значений (суммирование); столько же присваиваний. Значит быстрее процентов на 30. Если у человека за плечами хорошая математическая школа, то можно даже увидеть точное количество сэкономленных операций и более аргументированную оценку эффективности оптимизации.
Теперь самое время для главного удара. Запускаем оба варианта кода на каком-нибудь достаточно большом значении n (порядка нескольких тысяч), например, так .

Код с контролем времени

class A { public static void main(String args) { int n = 8000; int g = new int[n][n]; long st, en; // one st = System.nanoTime(); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { g[i][j] = i + j; } } en = System.nanoTime(); System.out.println("\nOne time " + (en - st)/1000000.d + " msc"); // two st = System.nanoTime(); for(int i = 0; i < n; i++) { g[i][i] = i + i; for(int j = 0; j < i; j++) { g[j][i] = g[i][j] = i + j; } } en = System.nanoTime(); System.out.println("\nTwo time " + (en - st)/1000000.d + " msc"); } }


Что же мы видим? Оптимизированный вариант работает в 10-100 раз медленнее! Теперь самое время понаблюдать за реакцией претендента на должность. Какая будет реакция на необычную (точнее обычную в практике разработчика) стрессовую ситуацию. Если на лице подзащитного изобразился азарт и он стал жать на кнопочки временно забыв о Вашем существовании, то это хороший признак. До определенной степени. Вы ведь не хотите взять на работу исследователя, которому плевать на результат проекта? Тогда не задавайте ему вопрос «Почему?». Попросите переделать второй вариант так, чтобы он действительно работал быстрее первого.
Теперь можно смело заниматься некоторое время своими делами. Через пол часа у Вас будет достаточно материала, для того, чтобы оценить основные личностные и профессиональные качества претендента.
Кстати, когда я коротко описал эту задачку на своем рабочем сайте, то наиболее популярный комментарий был «Вот такая эта Ваша Java кривая». Специально для них выкладываю код на Великом и Свободном. А счастливые обладатели Free Pascal под Windows могут заглянуть

под спойлер

program Time; uses Windows; var start, finish, res: int64; n, i, j: Integer; g: Array of Array of Integer; begin n:= 10000; SetLength(g, n, n); QueryPerformanceFrequency(res); QueryPerformanceCounter(start); for i:=1 to n-1 do for j:=1 to n-1 do g := i + j; QueryPerformanceCounter(finish); writeln("Time by rows:", (finish - start) / res, " sec"); QueryPerformanceCounter(start); for i:=1 to n-1 do for j:=1 to n-1 do g := i + j; QueryPerformanceCounter(finish); writeln("Time by cols:", (finish - start) / res, " sec"); end.


В приведенном коде на Паскале я убрал «запутывающие» моменты и оставил только суть проблемы. Если это можно назвать проблемой.
Какие мы в итоге получаем вопросы к подзащитному?
1. Почему стало работать медленнее? И поподробнее…
2. Как сделать инициализацию быстрее?

Если есть необходимость копнуть глубже именно в реализацию Java, то просим соискателя понаблюдать за временем выполнения для небольших значений n . Например, на ideone.com для n=117 «оптимизированный» вариант работает вдвое медленнее. Но для следующего значения n=118 он оказывается уже в 100 (сто) раз быстрее не оптимизированного! Предложите поэкспериментировать на локальной машине. Пусть поиграет с настройками.
Кстати, а всем понятно, что происходит?

Несколько слов в оправдание

Хочу сказать несколько слов в оправдание такого способа собеседования при найме. Да, я не проверяю знание синтаксиса языка и владение структурами данных. Возможно, при цивилизованном рынке труда это все работает. Но в наших условиях тотальной нехватки квалифицированных кадров, приходится оценивать скорее перспективную адекватность претендента той работе с которой он столкнется. Т.е. способность научиться, прорваться, разобраться, сделать.
По духу это похоже на «собеседованию» при наборе легионеров в древнем Риме. Будущего вояку сильно пугали и смотрели краснеет он или бледнеет. Если бледнеет, то в стрессовой ситуации у претендента кровь отливает от головы и он склонен к пассивной реакции. Например, упасть в обморок. Если же соискатель краснел, то кровь у него к голове приливает. Т.е. он склонен к активным действиям, бросаться в драку. Такой считался годным.
Ну и последнее. Почему я рассказал об этой задаче всем, а не продолжаю использовать её на собеседованиях? Просто, эту задачу уже «выучили» потенциальные соискатели и приходится использовать другие.
Собственно на этот эффект я обратил внимание именно в связи с реальной задачей обработки изображений. Ситуация была несколько запутанная и я не сразу понял почему у меня так просел fps после рефакторинга. А вообще таких чуднЫх моментов наверное много накопилось у каждого.

Пока лидирует версия, что «виноват» кэш процессора. Т.е. последовательный доступ в первом варианте работает в пределах хэша, который обновляется при переходе за определенную границу. При доступе по столбцам хэш вынужден постоянно обновляться и это занимает много времени. Давайте проверим эту версию в самом чистом виде. Заведем массив и сравним, что быстрее - обработать все элементы подряд или столько же раз обработать элементы массива со случайным номером? Вот эта программа - ideone.com/tMaR2S . Для 100000 элементов массива случайный доступ обычно оказывается заметно быстрее. Что же это означает?
Тут мне совершенно справедливо указали (Big_Lebowski), что перестановка циклов меняет результаты в пользу последовательного варианта. Пришлось для чистоты эксперимента поставить цикл для разогрева. Заодно сделал несколько повторов, чтобы вывести среднее время работы как советовал leventov. Получилось так ideone.com/yN1H4g . Т.е. случайный доступ к элементам большого массива на ~10% медленнее чем последовательный. Возможно и в правду какую-то роль может сыграть кэш. Однако, в исходной ситуации производительность проседала в разы. Значит есть еще что-то.

Постепенно в лидеры выходит версия про дополнительные действия при переходе от одной строки массива к другой. И это правильно. Осталось разобраться, что же именно там происходит.

Теги: Добавить метки

Массив – это набор однотипных переменных, на которые ссылаются по общему имени. Массивы можно создавать из элементов любого типа, и они могут иметь одно или несколько измерений. К определенному элементу в массиве обращаются по его индексу (номеру). В заметке мы рассмотрим обработку одномерных и двумерных массивов.

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

Одномерный массив – это, по существу, список однотипных переменных. Чтобы создать массив, сначала следует создать переменную массива (array variable) желательного типа. Общий формат объявления одномерного массива:
type var-name ;
Здесь type объявляет базовый тип массива; var-name – имя переменной массива. Базовый тип определяет тип данных каждого элемента массива. Например, объявление одномерного массива int-компонентов с именем month_days имеет вид:
int month_days ;
Хотя это объявление и устанавливает факт, что month_days является переменной массива, никакой массив в действительности не существует. Фактически, значение month_days установлено в null (пустой указатель), который представляет массив без значения. Чтобы связать month_days с факти­ческим, физическим массивом целых чисел, нужно выделить память для него, используя операцию new , и назначать ее массиву month_days ; new – это специальная операция, которая распределяет память.

Общий формат new в применении к одномерным массивам имеет вид:
array-var = new type ;
где type – тип распределяемых данных, size – число элементов в массиве, array-var– переменная, которая связана с массивом. Чтобы использовать new для распределения памяти под массив, нужно специфицировать тип и число элементов массива. Элементы в массиве, выделенные операцией new , будут автоматически инициализированы нулями. Следующий пример распределяет память для 12-элементного массива целых чисел и связывает его с переменной month_days .
month_days = new int;
После того как эта инструкция выполнится, month_days будет ссылаться на массив из двенадцати целых чисел. Затем все элементы в массиве будут инициализированы нулями.
Процесс получения массива включает два шага. Во-первых, следует объявить переменную массива желательного типа. Во-вторых, необходимо выделить память, которая будет содержать массив, используя операцию new , и назначать ее переменной массива. Таким образом, в Java все массивы явля­ются динамически распределяемыми.

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

Возможна комбинация объявления переменной типа массив с выделением массиву памяти непосредственно в объявлении:
int month_days = new int;

Рассмотрим код программы, выполняющей замену отрицательных элементов массива на максимальный элемент:

Public class FindReplace { public static void main(String args) { int myArray; // объявление без инициализации int mySecond = new int; /* выделение памяти с инициализацией значениями по умолчанию */ int a = {5, 10, 0, -5, 16, -2}; // объявление с инициализацией int max = a; for (int i = 0; i < a.length; i++) { if (a[i]<0) a[i] = max; mySecond[i] = a[i]; System.out.println("a[" + i + "]=" + a[i]); } myArray = a; // установка ссылки на массив a } }

В результате выполнения будет выведено:

>java FindReplace a=5 a=10 a=0 a=5 a=16 a=5

Присваивание mySecond[i] = a[i] приведет к тому, что части элементов массива mySecond , а именно шести, будут присвоены значения элементов массива a . Остальные элементы mySecond сохранят значения, полученные при инициализации, то есть нули. Если же присваивание организовать в виде mySecond = a или myArray = a , то оба массива участвующие в присваивании получат ссылку на массив a , то есть оба будут содержать по шесть элементов и ссылаться на один и тот же участок памяти.
Массивы можно инициализировать во время их объявления. Процесс во многом аналогичен тому, что используется при инициализации простых ти­пов. Инициализатор массива – это список разделенных запятыми выражений, окруженный фигурными скобками. Массив будет автоматически создаваться достаточно большим, чтобы содержать столько элементов, сколько вы определяете в инициализаторе массива. Нет необходимости использовать операцию new . Например, чтобы хранить число дней в каждом месяце, сле­дующий код создает инициализированный массив целых чисел:

Public class MonthDays { public static void main(String args) { int month_days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; System.out.println("Апрель содержит " + month_days + " дней."); } }

В результате выполнения программы на экран будет выведено:

Апрель содержит 30 дней.

Замечание: Java делает строгие проверки, чтобы удостовериться, что вы случайно не пробуете сохранять или читать значения вне области хранения массива. Исполнительная система Java тоже делает тщательные проверки, чтобы убедиться, что все индексы массивов находятся в правильном диапазоне. (В этом отношении Java существенно отличается от языков C/C++ , которые не обеспечивают проверки границ во время выполнения).

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

В Java многомерные массивы – это, фактически, массивы массивов. Они выглядят и действуют подобно регулярным многомерным массивам. Однако имеется пара тонких различий. Чтобы объявить многомерную переменную массива, определите каждый дополнительный индекс, используя другой набор квадратных скобок. Например, следующее утверждение объявляет переменную двумерного массива с именем twoD:
int twoD = new int;
Оно распределяет память для массива 4x5 и назначает ее переменной twoD . Внутренне эта матрица реализована как массив массивов целых чисел тип int .
Многомерные массивы возможно инициализировать. Для этого просто включают инициализатор каждого измерения в его собственный набор фи­гурных скобок.
В следующей программе создаются и инициализируются массивы массивов равной длины (матрицы), и выполняется произведение одной матрицы на другую:

Public class Matrix { private int a; Matrix(int n, int m) { // создание и заполнение с random a = new int[n][m]; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) a[i][j] = (int) (Math.random()*5); show(); } public Matrix(int n, int m, int k) { // создание и заполнение с random a = new int[n][m]; for (int i = 0; i < n; ++i) for (int j = 0; j < m; ++j) a[i][j] = k; if (k != 0) show(); } public void show() { System.out.println("Матрица:" + a.length + " на " + a.length); for (int i = 0; i < a.length; ++i) { for (int j = 0; j < a.length; ++j) System.out.print(a[i][j] + " "); System.out.println(); } } public static void main(String args) { int n = 2, m = 3, z = 4; Matrix p = new Matrix(n, m); Matrix q = new Matrix(m, z); Matrix r = new Matrix(n, z, 0); for (int i = 0; i < p.a.length; ++i) for (int j = 0; j < q.a.length; ++j) for (int k = 0; k < p.a[i].length; ++k) r.a[i][j] += p.a[i][k]*q.a[k][j]; System.out.println("Произведение матриц: "); r.show(); } }

Так как значения элементам массивов присваиваются при помощи метода random() , то одним и вариантов выполнения кода может быть следующий:

> javac Matrix.java > java Matrix Матрица:2 на 3 3 2 0 3 3 1 Матрица:3 на 4 1 2 2 3 3 2 3 2 1 2 3 2 Произведение матриц: Матрица:2 на 4 9 10 12 13 13 14 18 17

Следующий пример демонстрирует копирование массива:

Public class ArrayCopyDemo { public static void main(String args) { int mas1 = {1,2,3}, mas2 = {4,5,6,7,8,9}; System.out.print("mas1: "); show(mas1); System.out.print("mas2: "); show(mas2); // копирование массива mas1 в mas2 System.arraycopy(mas1, 0, mas2, 2, 3); /* 0 - mas1 копируется начиная с нулевого элемента * 2 - элемент, с которого начинается замена * 3 - количество копируемых элементов */ System.out.println("\n после arraycopy(): "); System.out.print("mas1: "); show(mas1); System.out.print("\nmas2: "); show(mas2); } private static void show(int mas) { for (int i = 0; i < mas.length; ++i) System.out.print(" " + mas[i]); } }

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

> javac ArrayCopyDemo.java > java ArrayCopyDemo mas1: 1 2 3mas2: 4 5 6 7 8 9 после arraycopy(): mas1: 1 2 3 mas2: 4 5 1 2 3 9

Альтернативный синтаксис объявления массива

Существует иная форма, которая может использоваться для объявления массива:
type var-name;
Здесь квадратные скобки следуют за спецификатором типа, а не именем переменной массива. Например, следующие два объявления эквивалентны:

Int al = new int; int a2 = new int;
Представленные здесь объявления также эквивалентны:
char twodi = new char; char twod2 = new char;
Эта альтернативная форма объявления включена, главным образом, для удобства.

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

Для примера рассмотрим двумерный массив в Java.

Двумерные массивы Java - это прямоугольная или не прямоугольная таблица чисел.

Двумерный массив Java состоит из рядов и столбцов.

Первый индекс двумерного массива Java - это число рядов.

Пример двумерного прямоугольного массива Java:

Int multyArr; multyArr = new int; /* * multyArr structure * | (0,0) | (0,1) | * | (1,0) | (1,1) | */

Здесь объявлен и определен двумерный массив, имеющий две строки и два столбца.

Загрузим массив элементами:

MultyArr = 1; multyArr = 2; multyArr = 3; multyArr = 4;

Вывод двумерного массива (перебираем массив):

System.out.println("multyArr"); for(int inn = 0; inn < 2; inn++) { for(int jnn = 0; jnn < 2; jnn++) { System.out.println("multyArr[" + inn + "][" + jnn + "] = " + multyArr ); } }

Получаем:

for(int inn = 0; inn < 2; inn++)

мы проходим по рядам, а в цикле

for(int jnn = 0; jnn < 2; jnn++)

по столбцам.

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

int multyArr = {{1,2}, {3,4}};

Длина многомерного массива в Java

Int multyArr = {{1,2}, {3,4}, {5,6}}; /* * multyArr structure * | 1 | 2 | * | 3 | 4 | * | 5 | 6 | */ System.out.println("Array length = " + multyArr.length);

Array length = 3

Здесь три ряда по два элемента каждый. Первая размерность - три, это и есть длина двумерного массива.

Трехмерный массив в Java

Пример трехмерного массива в Java:

int triArray;
triArray = new int;

Здесь объявлен и определен трехмерный массив. Его можно представит как куб, состоящий из двух слоёв (layer), каждый слой состоит из двух рядов и двух столбцов, т.е. каждый слой - это двумерный массив.

Как заполнить трехмерный массив? Можно в цикле, но мы для примера вручную заполним:

//**************** //THE FIRST LAYER //**************** //the first row of the first layer triArray = 1; triArray = 2; //the second row of the first layer triArray = 3; triArray = 4; //**************** //THE SECOND LAYER //**************** //the first row of the second layer triArray = 5; triArray = 6; //the second row of the second layer triArray = 7; triArray = 8;

Как вывести трехмерный массив? Или как перебрать трехмерный массив? Так.

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

Массивы относятся к ссылочным типам данных , собственно как и все остальные типы, кроме примитивных. Напомню еще раз, что в Java все является объектом, исключение составляют лишь примитивные типы.

Массивы могут быть одномерными и многомерными.

Процесс создания массива можно разделить на три этапа:

  • Объявление (declaration )
  • Создание (instantation )
  • Инициализация (initialization )

Объявление (declaration) массива

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

numbers ; // numbers ссылка на массив int-ов
String str ; // str ссылка на массив строк
byte
twoBytes ; // twoBytes ссылка на двумерный массив байтов
char
letters , digits ; //letters и digits ссылки на массивы символов

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

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

arrayOfBytes ; // То же, что и byte arrayOfBytes
byte arrayOfArrayOfBytes ; // То же, что и byte arrayOfArrayOfBytes
byte arrayOfArrayOfBytes ; // То же, что и byte arrayOfArrayOfBytes

Однако зачастую такой синтаксис сбивает с толку, поэтому его следует избегать. В следующем примере, легко спутать что имелось в виду:

rates , maxRate ; // может хотели объявить два массива?

Такой синтаксис не рекомендуется использовать, так как уже говорилось, что он сбивает с толку, кроме того, в соглашения по оформлению Java кода, рекомендуется синтаксис, который был приведен первым, то есть квадратные скобки следуют сразу за типом объявляемого массива.

В данном случае объявлены массив значений типа float с именем rates и переменная типа float – maxRate.

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

Следует понимать, что данная операция объявления массива еще не создает массив, а только объявляет переменную являющуюся ссылкой на него , которую без инициализации нельзя использовать в программе, так как компилятор выдаст ошибку, что переменная массива не инициализирована.

Пока объявленная переменная массива не определена, она может содержать (если вы присвоите) значение null . И только после определения она будет содержать ссылку на конкретный объект.

Указать длину массива при объявлении переменной массива невозможно, поскольку размер является строго функцией объекта массива, а не ссылки на него .

Создание (instantation) массива

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

= new char [ 10 ] ;

Но стоит еще раз заметить, что до этого переменная letters, должна быть объявлена как массив. Чтобы было более понятно, это можно представить вот так:

letters ; // объявили letters как ссылку на массив символов char
letters = new char [ 10 ] ; // создали массив char-ов размеров в 10 элементов

При создании массива с таким синтаксисом все элементы массива автоматически инициализируются значениями по умолчанию . Это false для значений boolean, "\u0000" для значений char, 0 для целых значений, 0.0 для значений с плавающей точкой и null для объектов или массивов.

В Java размер массива фиксирован. Созданный массив нельзя увеличить или уменьшить. Желаемый размер создаваемого массива задается неотрицательным целым числом . Но в любое время переменной типа массива может быть сопоставлен новый массив другого размера. То есть может быть присвоена ссылка на другой массив того же типа что и объявленная переменная.

Индексы массивов всегда начинаются с 0 .

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

letters = new char [ 10 ] ;

Этот оператор эквивалентен двум приведенным выше.

После данной операции переменная letters будет уже содержать ссылку на массив и если попробовать вывести ее значение то мы получим значение, что то вроде ;
int b = a ;

Но надо иметь в виду, что переменные a и b указывают на один и тот же массив. По началу это может сбивать с толку, но если помнить что мы имеем дело с ссылочными типами данных, то все становится на свои места. Если этот момент не понятен, то чуть позже мы все это разберем на примерах.

= null ;

После этого массив, на который указывала данная ссылка, теряется, если на него не было других ссылок .

Размер или длину массива можно получить при помощи константы length , которая определена для каждого массива и возвращает его длину. Мы ей уже не раз пользовались в примерах когда работали с аргументами переданной в командной строке.

Можно создавать и использовать массивы нулевой длины (пустой массив). Например:

bits = new boolean [ 0 ] ;

Инициализировать такой массив нельзя, так как у него просто нет элементов которые можно инициализировать. Сразу же возникает вопрос, а на кой ляд они тогда вообще нужны эти пустые массивы? Но они нужны и даже очень полезны!

Пустой массив принято использовать в тех местах программы, где заранее неизвестно, будут элементы или нет. Если элементы будут, то возвращается непустой массив, если элементов нет - пустой массив. Примером может служить массив строк который передается в метод main() и содержит аргументы командной строки, а если их нет, то возвращается пустой массив.

Пустой массив лучше, чем null , потому что не требует отдельного if"а для обработки. То же верно для списков и других коллекций. Именно поэтому существуют методы Collections.emptyList, emptySet, emptyMap.

Инициализация (initialization) массива

На этом этапе элементы массива получают начальные значения. Инициализировать элементы массива значениями можно несколькими способами:

  1. Присвоить каждому элементу массива конкретное значение (это можно сделать например в цикле, но до этого массив уже должен быть объявлен и создан)
  2. Инициализировать массив при помощи перечисления значений его элементов в фигурных скобках (это можно сделать как на этапе объявления, так и на этапе создания, но синтаксис при этом разный)

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

Индексы можно задавать любыми целочисленными выражениями, кроме типа long , например a , a , a[++i] . Исполняющая система Java следит за тем, чтобы значения этих выражений не выходили за границы длины массива. Если же выход все же произойдет интерпретатор Java в таком случае прекратит выполнение программы и выведет на консоль сообщение о выходе индекса массива за границы его определения (ArrayIndexOutOfBoundsException ).

Рассмотрим пример первого способа инициализации:

ar = new int [ 2 ] ;
ar [ 0 ] = 1 ;
ar [ 1 ] = 2 ;

Второй способ инициализации можно реализовать по разному.

Инициализацию массива можно совместить с этапом создания, но до этой операции массив уже должен быть объявлен . Например:

ar ; // объявление массива
ar = new int { 1 , 2 } ; // создание и инициализация

До создания и инициализации массива ar он уже был объявлен.

Так же инициализировать массив можно на этапе его объявления следующим синтаксисом:

ar = { 1 , 2 } ; // объявление, создание и инициализация массива

Внимание! Этот синтаксис инициализации массива работает только при объявлении массива и совмещает сразу все три операции объявление, создание и инициализацию. Если массив уже объявлен, то такой синтаксис использовать нельзя. Компилятор выдаст ошибку. То есть:

int ar ; // объявление массива
ar = { 1 , 2 } ; // ОШИБКА!!! создание и инициализация массива

Такое действо не прокатит.

Так же можно инициализировать на этапе объявления и чуть чуть по другому:

ar = new int { 1 , 2 } ; // объявление, создание и инициализация

Хотя этот синтаксис более длинный. Если вы заметили, то данный синтаксис это тоже совмещение всех трех операций: объявления, создания и инициализации.

В Java предусмотрен синтаксис, который поддерживает анонимные массивы (они не присваиваются переменным и, следовательно, у них нет имен). Иногда массив нужно задействовать лишь один раз (например, передать его методу), следовательно, вы не хотите тратить время на присваивание его переменной, поэтому можно сразу же использовать результат оператора new . Например:

. out . println ( new char { "H" , "e" , "l" , "l" , "o" }) ;

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

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

perfectNumbers = { 6 , 28 } ;

Он компилируется в такой байт-код Java:

perfectNumbers = new int [ 2 ] ;
perfectNumbers [ 0 ] = 6 ;
perfectNumbers [ 1 ] = 28 ;

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

Однако тот факт, что Java инициализирует массив во время выполнения программы, имеет важные последствия. Это означает, что элементы массива-литерала являются произвольными выражениями, вычисляемыми во время выполнения программы, а не постоянными выражениями, вычисляемыми компилятором . Например:

points = { circle1.getCenterPoint () , circle2.getCenterPoint () } ;

Теперь немножко попрактикуемся.

В хорошо нам известном методе main(), как раз и используется возможность возврата массива нулевой длины если в командной строке нет аргументов, что позволяет избежать использования оператора if для проверки на null, дабы избежать ошибки во время исполнения программы.

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

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

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

Данная программа генерирует следующий вывод:

В первом случае мы не вводили ни каких аргументов, поэтому получили массив нулевой длины, который не был обработан в циклах, поскольку не удовлетворяет условиям циклов.

Во втором случае мы передали аргументы в командной строке и следовательно массив был обработан в циклах.