В предыдущих статьях мы познакомились с основными возможностями Java для написания объектно-ориентированных программ. Попробуйте критически переосмыслить все, что было описано, со следующей точки зрения: Вам, как разработчику программ, предоставляется набор инструментов, которые можно использовать для построения своих программ. Какие-то конструкции подходят для одних случаев, другие — для других. Чем больше у Вас появляется опыта в использовании базовых конструкций, тем проще воспринимаются более сложные моменты. Накапливается опыт и Ваш инструментарий расширяется — Вы знакомитесь и уже понимаете как надо использовать новые конструкции и понятия. Увы, но простым чтением для накопления опыта не обойтись — надо писать программы. Только практика может помочь Вам освоиться.
Но прежде чем мы продолжим знакомиться с другими конструкциями Java для работы с классами, я бы хотел предложить познакомиться с весьма заслуженной конструкцией данных — массивами.

Массивы

Если попробовать дать определение массиву, то на мой взгляд оно должно выглядеть так: Массивом называется множество однотипных объектов, объединенных одним именем и доступ к каждому объекту в этом множестве осуществляется по порядковому номеру (индексу).
Важно отметить, что сам по себе массив — это объект, а значит ему присущи те же особенности. что и объекту — его надо создать, у него есть некоторые поля и методы, которые Вы можете использовать для работы. Использование массивов на сегодня не является сильно распространенным явлением, но они занимают достаточно нужную и прочную нишу в современном инструментарии, так что знакомство с ними весьма важно. Давайте знакомиться.
В первую очередь нам необходимо узнать как описать массив и как его создать. Как говорила моя бабушка (хотя такое говорили наверно многие бабушки), повторение мать учения. Так что вернемся опять к нашему роботу. Если Вы забыли, то вот его код.

Класс Robot остался таким же каким он был и раньше, а вот класс RobotManager содержит объявление массива роботов и создание массива.

Т.е. для объявления массива мы пишем сначала имя класса, объекты которого будут составлять массив, после них пустые квадратные скобки и имя переменной. Эта переменная — ссылка на массив. Для создания массива мы используем ключевое слово new, снова пишем класс и квадратные скобки, внутри которых указываем размер массива. Как и обычную переменную, мы можем совместить объявление массива и его создание в одну строку. Вот так:

Теперь в переменной rbts находится ссылка на массив из десяти ссылок на роботов. Я не оговорился и предлагаю Вам еще раз внимательно прочитать предыдущую фразу — массив rbts содержит десять ссылок на объекты типа Robot. Т.к. это десять ссылок, то после создания массива каждая из этих ссылок содержит величину null. попробуем убедиться, что так оно и есть. Для этого обратимся к каждой ссылке из массива rbts по индексу. Для того, чтобы обратиться к конкретному элементу массива опять используются квадратные скобки, внутри которых указывается порядковый номер (индекс). Важно отметить, что номера (индексы) начинаются со значения 0. Т.е. обращение rbts[1] означает обращение ко второму (не к первому) элементу в массиве rbts. При размере массива в 10 элементов, индекс последнего будет равен 9. Единственное требование к индексу — это должно быть целое число. Причем может использоваться переменная, а не только константа. Подкрепим наши новые знания практикой — обратимся к каждому элементу массива rbts

На самом деле все достаточно просто — в цикле меняется значение переменной i, которая и помогает нам обратиться к нужному элементу массива rbts. Само обращение к элементу массива выглядит вот так:rbts[i]. Это обращение практически не отличается от обращения к обычной переменной. И как я уже упоминал, пока в наших переменных ничего нет, в чем мы и могли убедиться, увидев надписи null в количестве 10 штук. Теперь инициализируем наши переменные, а заодно познакомимся с одним важным свойством массива — как можно узнать его размер.

У нас теперь два цикла. Первый служит для создания объектов типа Robot, а второй вызывает для каждого метод для печати его координат. Обратите внимание, что теперь мы используем свойство массива length — это позволяет писать более гибкий код. Мы можем создать 15, 43 или 17 объектов и для этого код циклов менять не надо. Это упрощает разработку и избавляет от лишних ошибок. При создании робота мы используем конструктор, который принимает в качестве входных параметров координаты X и Y. Более внимательно посмотрев на код видно, что каждый робот получает координаты, которые пропорциональны его индексу в массиве.

Таким образом работа с массивом — это работа с отдельными его элементами при помощи изменения значения индекса. Именно через индекс Вы можете обратиться к любому объекту внутри массива. Что это нам дает ? Возможность работы с группой объектов с помощью одной переменной, что упрощает создание программ. Представьте, что что у Вас была бы необходимость работать с парой сотен роботов. Будете описывать две сотни переменных ? Или Вы вообще заранее не знаете, сколько роботов надо будет использовать. В случае объявления массива Вам это уже не так важно — 10 или 100. Если Вы имеете алгоритм для управления всеми этими роботами через индекс, то количество Вас уже не смущает.

Начав работу с массивами, мы сразу стали создавать массивы со сложными типами данных — классами. И убедились, что принципы создания объектов остались такими же, как и для обычного объекта — надо обязательно создать объект внутри массива. Само создание массива порождает только набор ссылок (в нашем примере 10 ссылок на объекты типа Robot). И только после создания объектов для КАЖДОЙ ссылки мы получаем полноценный набор объектов внутри массива.
Но мы также знакомились в элементарными типами — byte, int, double. В случае объявления переменной элементарного типа, как Вы возможно помните, создавать ее не надо — она существует сразу при объявлении. Ее надо только инциализировать — Для массивов этот принцип точно такой же — создавая массив целых чисел, вы сразу получаете целые числа, с которыми можно работать. В спецификации языка Java указано, что переменные элементарных типов инициализируются при создании. Для чисел это 0. Рассмотрим простой пример:

По результатам исполнения примера можно видеть. что начальные значения всех элементов массива — число 0. Предлагаю рассмотреть несколько достаточно простых примеров работы с массивами. Примеры не сложные и существуют уже многие годы.
Первый пример — необходимо сосчитать сумму все чисел массива. В этом примере мы увидим любопытную конструкцию инициализации элементов массива. Сам алгоритм достаточно несложный — кроме массива создается переменная, которая будет «накапливать» сумму всех элементов. Т.е. проходя в цикле по всем элементам мы будем прибавлять значение каждого элемента к переменной, начальное значение которой должно быть равно нулю. Смотрим реализацию.

Конструкция инициализации массива записывается просто — внутри фигурных скобок через запятую вводятся нужные числа. Запись достаточно лаконичная и наглядная, но имеет существенный недостаток — набор элементов массива жестко «забит» в коде, что не всегда является удобным. Важно отметить, что внутри скобок можно создавать объекты. Например для создания массива из трех роботов можно написать вот такую конструкцию:

Дальше в примере создается переменная summa, которая инициализируется нулевым значением и уже в цикле к ней прибавляется каждый элемент массива. Вот и все.
Следующий пример тоже может быть признан классикой — это сортировка массива методом «пузырька». Далеко не самый эффективный способ сортировки, но в качестве примера очень даже неплохо. Сортировка производится по следующему алгоритму: сравниваются два находящихся рядом элемента массива. Если первый элемент больше второго, то их надо поменять местами. При каждом проходе по всему массиву элементы с меньшим значением потихонечку передвигаются к началу — «всплывают». Отсюда и название метода. Проход по всем элементам повторяется до тех пор, пока хоть одна пара элементов поменялась местами.

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

Цикл foreach

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

Самой главной в этом примере является строка for (int t : sample) {. Эту запись можно интепретировать следующим образом — цикл проходит по всем элементам массива, каждый раз помещая в переменную t значение следующего элемента массива. Т.е. при каждом проходе цикла в переменной t последовательно будет появляться значение sample[0], sample[1], sample[2] и т.д.
Цикл выглядит более компактно и пользоваться им удобно. Но существует важная особенность, о которой надо обязательно помнить. Я только что ее проговорил, но повторю еще раз: «при каждом проходе цикла в переменной t последовательно будет появляться значение». Иными словами, в переменную t КОПИРУЕТСЯ значение из элемента массива. Таким образом получается, что перменная t и переменная sample[0] — это РАЗНЫЕ переменные. Рассмотрим более сложный пример:

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

Разница между этими примерами в средней части — посмотрите внимательно.
На этом мы закончим первое знакомство с массивами. В современном мире программирования массивы уже не так популярны, как лет 20 назад. У них есть своя ниша, где они применяются, но на мой взгляд сегодня они уступили свои позиции более современным структурам данных. массивы имеют ряд недостатков, среди которых важным является то. что их размер определяется сразу при их создании и изменить его достаточно сложно. Тем не менее знание массивов должно быть в Вашем арсенале. В следующей части мы продолжим знакомство с массивами и рассмотрим более сложные примеры их использования.

Архивы примеров, арссмотренных в данном разделе можно скачать здесь — RobotArray и ArrayDemo.

7 comments to Массивы — знакомство

  • Vladimir  says:

    Уважаемый Админ.
    Поясните, как отрабатывает код из класса очередь примера предыдущего урока «очередь объектов»:
    // Перемещаем «голову» на следующий элемент
    head = head.getNext();
    ведь, насколько я понимаю, head.getNext() должен вернуть значение поля next объекта head, но мне не понятно, как когда и чем это поле было заполнено при реализации метода pull.
    Еще вопрос: для прохождения курса «Начальный курс Java», необходимо ли пройти материалы выложенных на сайте уроков.

    • admin  says:

      Метод pull не заполняет поле next — он им только пользуется. А заполнение происходит в методе push. Метод pull «вытаскивает» первый элемент в очереди. Если я вытащил первый элемент, то теперь уже следующий за ним (второй) должен стать первым. И значит head должен указывать на следующий, после вытаскиваемого (первого). Если в очереди только один элемент, то head будет указывать на null — пустая очередь.

  • Алекс  says:

    Уважаемый автор, мне также почему-то тяжело въехать в реализацию механизма «//Перемещаем «голову» на следующий элемент» из предыдущего урока.
    Насколько я понимаю, в данном участке кода метода pull() два указанных метода выполняются одним и тем же объектом класса ObjectBox (например, объектом ob1).

    // Получаем наш объект из вспомогательного класса из «головы»
    Object obj = head.getObject();
    // Перемещаем «голову» на следующий элемент
    head = head.getNext();
    // Если это был единственный элемент, то head станет равен null
    // и тогда tail (хвост) тоже дожен указать на null.

    Но тогда каким образом указатель head перемещается на следующий объект (например, ob2)? Это связано со спецификой хранения и обработки данных в памяти (типа после выполнения метода head.getObject() этот объект стирается?) или может быть next это какой-то оператор?

    И могли бы Вы прояснить еще один вопрос: каким образом заполняется поле next для первого объекта класса ObjectBox в методе push()(если объектов больше одного), когда участок кода

    else {
    // Если это не первый элемент, то надо, чтобы последний элемент в очереди
    // указывал на вновь прибывший элемент
    tail.setNext(ob);
    }

    для первого объекта не выполняется, т.к. правдиво условие if (head == null) ?

    • admin  says:

      Честно говоря не понял — это вопрос к какой статье ? В массивах мы об этом не говорили.

  • Алекс  says:

    Вопрос я задавал по уроку «Пример — очередь объектов». Просто там нет возможности добавить комментарий

    • admin  says:

      Исправил. Перенесите пожалуйста вопрос туда — так всем будет удобнее. Много у кого вопросы возникают

  • v  says:

    Конструкция

    действительно жесткая и неудобная для закачки случайных чисел (в качестве примера, например, «пузырька») можно применить

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.