Итак, продолжаем разговор, хоть и после долгого перерыва. Прошу простить за эту задержку - в жизни творится некоторая фигня.
Сегодня у нас массивы, циклы и на закуску - ещё кое-что о переменных:)
Ящики с пивомМассивы.
Массив - это набор значений одного типа. Представьте себе ящик пива, только такой, где бутылки стоят в один ряд, имеют разную степень наполненности и каждая бутылка пронумерована:) Вот можно считать, что это у нас массив бутылок пива:)
В Java можно создавать массивы любого типа, от примитивных до тех, что мы сами описали и определили. Мы рассмотрим массивы типа int. Объявляются массивы так:
int[] имя_массива;//вариант 0
int имя_массива[];//вариант 1
Оба объявления равнозначны и какое использовать - дело вкуса. Я лично предпочитаю 0-ой вариант:)
Итак, объявили массив. Круто, мы молодцы. Но его же ещё надо инициализировать. Делается это так:
имя_массива = new int[n];//вариант 0
имя_массива = new int[]{0, 1, 2, 3};//вариант 1
Я вижу панику на ваших лицах:) Уже который раз в кусках кода встречаются символы // с последующим текстом за ними, а я ещё не объяснил, что это такое:) Эти символы задают однострочный комментарий, то есть всё от этих символов и до конца текущей строки не воспринимается как программный код и не используется при построении приложения. Есть ещё последовательность /* ... */. Это не смайлик:) Это многострочный комментарий. Делает тоже самое, что и однострочный, но любой текст между этими символами не воспринимается комьютером как код программы. Такие вещи используют, когда нужно пояснить другим программистам да и себе, как работает какой-то кусок кода.
Вернёмся к тому, что мы тут написали. В варианте 0 мы создаём массив объектов типа int, содержащий в себе n объектов, а n - целое число, его можно указать явно цифирью, а можно передать инициализированную каким-то числом переменную. В этом случае, все n элементов массива равны 0 - это называется инициализация значением по умолчанию. Для каждого типа данных оно свое, для int это 0.
Вариант 1 делает тоже самое, но в фигурных скобках мы указываем элементы в том порядке, в котором они будут следовать в массиве и элементы массива инициализируются этими значениями, а не значениями по умолчанию. Вы можете сказать, что мы не указали размер, но в данном варианте это не страшно - компьютер умный, он сделает это за нас, посчитав количество указанных элементов:) Кстати, это единственный случай, когда за фигурной скобкой ставится ";", если фигурная скобка означает границу блока кода - там не нужна точка с запятой.
Объявление и инициализацию можно объединить и написать в одну строку. Но вы это уже видели на примере простых переменных, вы сможете это сделать:) Запомните ключевое слово new, оно вам очень понадобится. По сути это слово создает новый объект указанного класса.
Итак, объявили, инициализировали. Теперь нужно писать в массив или читать из него данные. Возвращаясь к аналогии с однорядным ящиком пива, нужно из каких-то бутылок наливать, в какие-то наливать:) Делается это очень просто - в квадратных скобках указывается индекс или номер нужного нам элемента. Например, приравнять значение элемента под номером 1 к значению элемента под номером 3 можно такой строчкой кода:
имя_массива[1] = имя_массива[3];
Кстати, вопрос на засыпку: чему был равен и будет равен 1-ый элемент нашего массива после выполнения этой строчки кода?:) Не угадали:) Был равен 1, стал равен 3. Не кидайте в меня тапками - я поясню:) Дело в том, что в программировании нумерация чего бы то ни было начинается с нуля. То есть индекс первого элемента(это у нас 0) равен 0, второго(он у нас 1) - 1 и так далее. Помните: максимальный номер элемента в массиве всегда на 1 меньше его размера. Если пытаться обратиться к элементу с номером 4 в массиве размером в 4 элемента, мы получим исключительную ситуацию - мы же вылезем за пределы массива. По аналогии с однорядным ящиком пива - мы попытаемся взять бутылку которой нет и никогда не было в ящике:)
С элементами массива можно производить те же операции что и с обычными переменными. А ещё можно сделать массив по аналогии с настоящим ящиком пива - многорядным:) Это называется двумерный массив. Как? А вот так:
int[][] имя_массива;//объявление
имя_массива = new int[10][10];//инициализация начальными значениями по умолчанию
int i = имя_массива[1][2];//переменной i присваиваем значение элемента в 1-ой строке 2-ом столбце
Всё тоже самое, только индексов теперь два. И доступ ведется по двум индексам. Для понимания проще представить таблицу или обычный ящик пива:) А можно сказать что это обычный массив у которого каждый элемент - массив значений типа int:) Кому что ближе:)
Последняя поправка для массивов - если вы создали массив определенного размера, изменить этот размер уже невозможно.
Циклы.
Цикл - повторяющийся несколько раз фрагмент кода. Циклы бывают с постусловием, с предусловием и обычный цикл. Начём с обычного, он же цикл for. Его синтаксис выглядит так:
for(инициализация счётчика; условие; изменение счётчика){
//повторяющийся блок кода или тело цикла
}
Теперь как это работает. Инициализация счётчика - это инициализация переменной, которая будет считать число проходов цикла. Она инициализируется один раз перед началом работы цикла, доступна в теле цикла и уничтожается после его завершения. Условие - логическое условие, если оно истиннно или true - цикл совершит очередной проход, если оно ложно или false - будет выполнена следующая за телом цикла строка кода. Изменение счётчика - выражение которое изменяет счётчик, как правило это инкремент или декремент, но может быть и любое другое арифметическое выражение.
Могу привести аналогию, навеянную телефонным звонком. У меня рингтон - свист падающих авиабомб:) Вот есть у нас бомбардировщик с определенным запасом бомб. И вот дают ему задание - энное количество раз отутюжить бомбами заданный район. Что получается: пилот выходит на цель, сбрасывает бомбы и улетает на базу за новым комплектом. И после каждого такого вылета считает их количество. Когда это самое количество вылетов достигнет определенного значения - всё, задание выполнил, можно заниматься своими делами:)
Ну, ещё можно привести аналогию с выпиванием энного количества бутылок пива:) Берем много бутылок и по очереди их выпиваем, считая количество. Как только количество достигло какого-то значения(мы стали "застенчивыми":)) - прекращаем это дело:)
Циклы очень удобны при работе с массивами. Например, нам нужно приравнять каждый элемент массива типа int на 100 элементов к какому-то опредленному значению. Это будет выглядеть так:
int [] arr = new int[100];
for(int i = 0; i < 100; i++){
arr[i] = 1000;
}
Вот так такой кусок кода и будет выглядеть. Разумеется в циклах можно выполнять не только такие простые действия, но и что-то посерьёзнее:)
Рассмотрим пошагово, что мы тут написали. Первая строка - объявление массива и инициализация значениями по умолчанию. Затем объявляется цикл, где переменная i это счётчик, который изначально равен 0, условие - i меньше 100, и инкремент в качестве изменения счётчика. На первом проходе i = 0, и элементу arr[0] присваивается значение 1000. Затем происходит увеличение счётчика на 1(инкремент). Затем проверяется условие и если оно истинно - проходит следующее повторение, которое называется итерацией. Когда i будет равно 100 - условие i < 100 не выполнится и тело цикла не выполнится. Вот так оно и работает.
Небольшое замечание: если бы мы определили переменную i до цикла, то она не уничтожилась бы после выполнения цикла, а сам цикл записался бы так:
int i;
for(i = 0; i < 100; i++){
arr[i] = 1000;
}
В этом случае, в последующих операциях переменная i будет доступна, в то время как в предыдущем варианте, переменная i уничтожится, когда цикл закончит свою работу.
Цикл с предусловием ещё называют циклом "пока". Выглядит конструкция так:
while(условие){
//повторяющийся блок кода или тело цикла
}
Суть ещё проще, чем в предыдущем цикле - пока указанное условие истинно, блок кода будет выполняться. Но есть одно "но": если на момент входа в цикл, то бишь первой итерации, каким-то непонятным образом условие окажется ложным - цикл не выполнится, вообще, никак, ни за что:)
Если рассматривать его в той же аналогии с бомбардировщиком, то получится так: пилоту дают задание бомбить заданный район, пока там не останется ничего живого. И он так же будет вылетать раз за разом и заходя в район цели смотреть, а есть ли там что живое и если нет - развернётся и возьмет курс на базу, а если есть - сбросит бомбы и вернётся на базу за дозаправкой и новыми бомбами:)
Если смотреть в аналогии про пиво, то это будет выглядеть так: допустим условие стоит пить пока не выпито всё. И вот перед каждой новой бутылкой пива мы будем проверять, а всё ли выпито, если нет - берем ещё бутылочку, если да - идём спать:)
Кстати, циклом while можно при некотором желании реализовать цикл for. А делается это вот так, если смотреть на предыдущий пример:
int[] arr = new int[100];
int i = 0;
while(i < 100){
arr[i] = 1000;
i++;
}
Этот блок кода делает тоже самое, что и предыдущий, просто объявление и прочее-прочее написаны по сути отдельно.
Цикл с постусловием - такая же байдистика, но проверка условия выполняется после отработки тела цикла, а не перед ней, как в двух предыдущих. Выглядит это так:
do{
//повторяющийся кусок кода или тело цикла
}while(условие);
Такой цикл используется, как правило, если тело цикла должно быть в любом случае выполнено хотя бы один раз.
Снова аналогия с бомбардировщиком:) Снова его посылают бомбить заданный район до состояния "выжженная земля", но теперь он сначала сбрасывает бомбы, а потом смотрит, осталось ли что живое. Если осталось - сделает ещё один вылет, если нет - вернётся на базу кофе пить:)
С пивом можно представить так:) Выпиваем бутылку и смотрим - а остались ли чипсы на закуску. Если остались - берем следующую бутылочку, если нет - идём спать:)
Перепишем ещё раз пример про массив, но уже на этом цикле:
int[] arr = new int[100];
int i = 0;
do{
arr[i] = 1000;
i++;
}while(i < 100);
Делает тоже самое, но в любом случае один раз выполнится.
Нельзя не упомянуть ещё один вид цикла for:
for(переменная : массив того же типа){
//тело цикла
}
В чём тут суть. Этот цикл перебирает все элементы указанного массива по очереди, а для доступа к ним используется переменная, указанная в определении цикла.
Снова вернёмся к бомбардировщику:) Пилоту дают задание разнести определенный набор(массив) целей, причём допустим, что на одну цель он тратит всю бомбовую нагрузку. Такой вот детёныш бомбардировщика:) Пилот переберет весь набор целей и после уничтожения одной вернётся на базу за очередным комплектом бомб, остались цели - ещё вылет, нет - идёт пить кофе:)
Про пиво... Хм... Допустим, у вас есть определенное количество бутылок пива, массив пивных бутылок, так сказать:) И вот вы перебираете все и каждую выпиваете:)
Наш несчастный кусок кода с массивом можно переписать ещё раз вот так:
int[] arr = new int[100];
for(int i : arr){
i = 1000;
}
Действует так же, выглядит короче:)
И нельзя упомянуть об операторе break, который порой используется в теле цикла. Вот допустим ситуацию, что вы в цикле что-то делаете, и вам при наступлении какого-либо условия нужно выйти из цикла. Для этого и используется волшебное слово break - оно прерывает выполнение тела цикла и программа выполняет уже те строки кода, которые за телом цикла.
Если по аналогиям - пилоту бомбардировщика пришёл приказ вернуться на базу и пить кофе, а в случае с пивом - пришла недовольная жена/девушка/соседи/полиция и пьянка кончилась:) Причём, как вы понимаете, такой приказ может прийти в любой момент: и во время вылета, и прямо перед сбросом бомбовой нагрузки, и когда пилот на базе
Например:
int i = 0;
for(i; i < 100; i++){
if(i == 50) break;
//Какие-то наши действия
}
System.out.prinln(i);
Его лучше использовать только с условием(об этом - в предыдущем посте), бо если в теле цикла просто стоит инструкция break;, дойдя до неё программа прервёт выполнение цикла и выйдет из него, а это может поломать весь алгоритм. И в итоге, программа будет работать не так, как надо.
В нашем примерчике цикл выполнится только наполовину, бо когда i станет равным 50, сработает наше условие, выполнится оператор break и произойдёт выход из цикла и выполнится строка с выводом.
Ещё кое-что о переменных.
Переменные же нужно называть, правильно? Так вот, называть их нужно правильно. Есть некоторые правила:
А ещё будет совсем зашибенно, если вы будете давать переменным осмысленные имена. Так будет проще разобраться в коде, да и читать его будет приятнее и удобнее:)
Ещё есть такая вещь, как область видимости переменных в коде. Одно определение. Блок кода - одна или несколько строк кода, заключенные в фигурные скобки {}. Помните, я говорил, что если переменная определена в цикле, после его отработки она будет недоступна? Так вот, такое бывает не только в циклах, а в любых внутренних блоках кода - те переменные, что определены во внутренних блоках кода, недоступны во внешних. А вот если определить переменную во внешнем блоке, например, в теле самого метода, то она будет доступна и во внешних блоках, и во внутренних. Пример сделаем такой, хоть и несколько притянутый за ухи:)
{
//Внешний блок кода
int extVar;
{
//Внутренний блок кода, здесь доступна extVar, а вот intVar будет доступна после её определения
int intVar;
//Теперь доступна и intVar
}
//Снова внешний блок кода. Здесь переменная intVar недоступна, а extVar - доступна
}
Обещенную программу я напишу чуть позже, бо листинг очень сильно увеличит размер поста, будет просто неудобно читать:)
Вопросы, замечания, дополнения, пожелания, комментарии - пишем в комментарии не стесняемся:)