Освой программирование играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

Основы

Ключевые слова

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

abstractassertbooleanbreakbyte
casecatchcharclassconst
continuedefaultdodoubleelse
enumextendsfinalfinallyfloat
forgotoifimplementsimport
instanceofintinterfacelongnative
newpackageprivateprotectedpublic
returnshortstaticstrictfpsuper
switchsynchronizedthisthrowthrows
transienttryvoidvolatilewhile

Формально слова true, false и null не входят в число ключевых слов, но их тоже нельзя использовать в качестве имён переменных. Обратите внимание, что Android Studio выделяет ключевые слова в редакторе кода особым цветом (синтаксическая подсветка).

Переменные

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

int x; // объявлена переменная под именем x
int y; // объявлена переменная под именем y

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

Переменные могут быть двух видов

  • примитивные типы: int, float, double, char и другие, которые представляют собой числа, символы
  • объекты, которые представляют классы

Список переменных примитивных типов рассматривается в следующей статье.

Переменной можно присвоить начальное значение (инициализировать) через знак равенства и указанием значения. Указываемое значение должно подходить типу, который вы указали для переменной. Для объявления нескольких переменных одного типа можно использовать запятые:


int c, a, t; // объявлены три переменные типа int
int p = 2, u, s = 7; // также объявлены три переменные, первая и третья при этом инициализированы

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


double a = 4, b = 5;
double c  = a + b; // переменная вычисляется динамически

В некоторых случаях нужно, чтобы переменная не менялась, в этом случае переменная называется константой и имеет ключевое слово final.

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


counter = 3; // вы используете переменную до его объявления. вы лох
int counter;

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

Если объявление переменной содержит инициализацию, то инициализация будет повторяться при каждом вхождении в блок, в котором она объявлена. Допустим, у нас есть блок:


int x;
for(x = 0; x < 5; x++) {
    int y = 42; // переменной y присваивается значение при каждом вхождении в блок
	y = 54;
}

При каждом вхождении в цикл переменной присваивается снова и снова значение 42. И хотя потом переменной присваивается значение 54, оно теряется при повторном вхождении в блок.

Блоки бывают вложенными, но тем не менее во внутреннем блоке нельзя объявлять переменные с тем же именем, что и во внешней области:


String cat = "Барсик";
{
    String cat = "Мурзик"; // переменная cat уже существует, так нельзя
}

Оператор присваивания

Оператором присваивания является одиночный знак равенства (=):


переменная = выражение;

Тип переменная должен соответствовать типу выражение. Оператор присваивания можно использовать в виде цепочки присваивания:


int x, y, z;
x = y = z = 9; // всем переменным присвоены значения 9

Оператор присваивания берёт значение правого выражения. Поэтому выражение z = 9 будет равно 9, после чего оно присваивается переменной y, а затем - переменной x.

Помните, что в сравнении используется другой оператор ==, а не оператор присваивания.

Комментарии

В Java используются три вида комментариев. Многострочные комментарии начинаются с символов /* и заканчиваются символами */. Однострочные комментарии начинаются с комбинации символов //. Причем, однострочный комментарий можно использовать не только на отдельной строке, но и после оператора.


/* Пример многострочного комментария
Вы здесь можете писать что угодно.
Например, мяу-мяу. И вам за это ничего не будет */

// однострочный комментарий на отдельной строке

Button resultButton; // это кнопка. Комментарий идет сразу после оператора в этой же строке

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

Существует ещё третий тип комментариев для создания самодокументирующего кода (комментарий документации). Но это отдельная тема для разговора.

В студии создание и управление комментариями можно упростить через меню Code. Там вы найдёте такие команды как Comment With Line Comment, Comment With Block Comment. Попробуйте самостоятельно разобраться с ними.

Backdoor!

С помощью комментария злобные программисты могут внедрить закладку в разрабатываемый софт. Если в комментариях программы использовать Unicode для переноса строки и после нее написать свой код, то IDE (Android Studio) будет отображать это как комментарий, но код будет выполняться.


public void onClick(View view) {
    // \u000a System.out.println("Hello Kitty!");
}

Backdoor

На первый взгляд, код не должен выполняться. Но это не так. Можете проверить.

\u000a — это Unicode-символ переноса строки (он же \n). Сначала производится декодирование, а потом уже разбор самого кода. Получается, что сначала произойдёт перенос, а потом будет напечатан рабочий код. Следующий пример тоже рабочий.


// \u000a\u0020System\u002eout.\u0070rintln("Hello Kitty!"\u0029;

Стиль оформления кода

Существует негласные правила оформления стиля при написании кода. Старайтесь их придерживаться. Также запоминайте оформление кода в документации и справочниках. Например, принято записывать имена классов с большой буквы (class JavaQuickCourseActivity). Если имя состоит из нескольких слов, то каждое слово в имени также начинается с большой буквы. Использовать символы подчеркивания или тире нежелательно (Java_Quick_Course_Activity или Java-Quick-Course-Activity).

Для методов и переменных используется такой же формат, только первый символ записывается с маленькой буквы, например, resultButton.

Константы принято писать только большими буквами - IDD_LIST_NAMES. В этом случае одного взгляда достаточно, чтобы сразу определить, что перед вами константа.

На первых порах вам этого достаточно.

Операторы

Как и везде, в Java есть операторы сложения (+), вычитания (-), умножения (*), деления (/), которые применимы к числам.

ОператорПример использованияОписание
+a + bСложение а и b (также унарный плюс)
++aПреобразование a в переменную типа int, если это переменная типа byte, short или char
-a – bВычитание b из а (также унарный минус)
--aАрифметическая инверсия а
*a * bУмножение а на b
/a / bДеление a на b
%a % bВычисление остатка от деления а на b (деление по модулю)
++a++Приращение а на 1 с предварительным вычислением значения а (инкремент)
++++aПриращение а на 1 с последующим вычислением значения а
--a--Уменьшение а на 1 с предварительным вычислением значения а (декремент)
----aУменьшение а на 1 с последующим вычислением значения а
+=a += bКраткая форма записи a = a + b (сложение с присваиванием)
-=a -= bКраткая форма записи a = a – b (вычитание с присваиванием)
*=a *= bКраткая форма записи a = a * b (умножение с присваиванием)
/=a /= bКраткая форма записи a = a / b (деление с присваиванием)
%=a %= bКраткая форма записи a = a % b (деление по модулю с присваиванием)

Операнды арифметических операторов должны иметь числовой тип. Нельзя использовать их к логическим типам. Можно применять к типам char, который по сути можно представлять как тип int.

Для строк можно использовать только операции + и +=. Умножать, вычитать и делить слова нельзя. Обратите внимание, что при сложении слов "мышь"+"мышь" получается не "мыши", как предположил мой кот Рыжик, а "мышьмышь". На самом деле символ + при работе со строками называется не сложением, а конкатенацией.

Оператор деления по модулю

Существует оператор, вычисляющий остаток от деления нацело (%). Чтобы запомнить данный знак, обратите внимание на наклонную черту, как в обычном делении, которую окружают два нолика. Деление нацело обрезает, а не округляет результат.

Если 42 разделить по модулю на 10, то получим значение 2, а если 42.56 разделить по модулю на 10, то получим 2.5600000000000023:


int x = 42;
double y = 42.56;

mInfoTextView.append("x mod 10 = " + x % 10 + "\n");
mInfoTextView.append("y mod 10 = " + y % 10 + "\n");

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


int iYear, twoDigit;
iYear = 2013;
twoDigit = iYear % 100;

mInfoTextView.setText(String.valueOf(twoDigit));

Вот и другой пример. Предположим, у вас есть фильм "Кот в сапогах", продолжительность которого равна 135 минутам. Чтобы разбить это число на часы и минуты, нужно применить такой код:


int filmTime = 135;
int hours = filmTime / 60;
int minutes = filmTime % 60;

mInfoTextView.setText("Кот в сапогах идёт " + hours + " часа " + minutes + " минут");

В результате получим ответ: Кот в сапогах идёт 2 часа 15 минут.

Обратите внимание, что переменная minutes всегда будет содержать числа в диапазоне от 0 до 59.

Стоит запомнить одну особенность. При делении большого числа на меньшее, например (5 % 4), понятно, что остаток будет 1. При делении по модулю меньших чисел 0, 1, 2, 3 на число 4 получатся те же значения 0, 1, 2, 3.

Напоследок, остаётся сказать, что делить на 0 нельзя. У вас будет выводиться сообщение об ошибке либо на этапе компиляции, либо во время работы программы.

В задачнике есть упражнения с применением данного оператора: 1, 2

Приоритет

Если вы не прогуливали уроки математики, то знаете, что в сложных выражениях скобки позволяют определить порядок вычислений. Например, в выражении 2 + 3 * 4 сначала идет умножение, а потом сложение. Расставив скобки, мы можем сначала сложить два числа, а потом умножить:

(2 + 3) * 4  // сначала складываем, потом умножаем

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

Укороченная форма записи

В Java также можно использовать укороченную форму записи, чтобы одновременно произвести операцию и присвоение. Для укороченной записи используется оператор с последующим знаком равенства. Например, чтобы прибавить число 7 к переменной x и присвоить результат этой же переменной, используйте команду x += 7. Это справедливо и для других операторов:


x += 7;
y -= 3;
cats *= 3;
numbersOfMouse /= 2;

Укороченная форма записи не только сокращает объём и время написания кода, но и работает более эффективно (хотя доказательств не знаю).

Автоувеличение и автоуменьшение на единицу

Очень часто вам придется увеличивать или уменьшать значение переменной на единицу. Поэтому существует специальные операторы увеличения (инкремента) и уменьшения (декремента). Для инкремента используются два плюса (++), а для декремента два минуса (--).

Данные операторы существуют в двух версиях - префиксной и постфиксной. Префиксный инкремент или декремент значит, что ++ или -- записываются перед переменной или выражением.


++i;
--i;

В этом случае сначала выполняется операция, а затем выдается результат.

При постфиксном инкременте или декременте оператор записывается после переменной или выражения:


i++;
i--;

Здесь сначала выдается значение, и лишь затем выполняется операция.

Например, мы хотим ежегодно увеличивать возраст кота в анкете:


int age = 3; // сейчас котёнку три года
age++; // увеличили на год

Данный код аналогичен более длинному варианту:


age = age + 1;

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

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


5++ // понимаю, мечтаешь о такой оценке в школе, но нельзя

По ссылке или по значению

У нас есть класс Cat


public class Cat {
    private String mCatName;

    Cat(String name) {
        mCatName = name;
    }

    public String getName() {
        return mCatName;
    }

    public void setName(String strName) {
        mCatName = strName;
    }
}

Попробуем, используя этот класс, передать объект Cat в метод и посмотреть, что получится:


void messWithCat(Cat kitty) {
    kitty = new Cat("Han");
}

void changeKitty(Cat kitty) {
    kitty.setName("Wookie");
}

Cat haveKitten() {
    Cat kitten = new Cat("Luke");
    return kitten;
}

Вызовем созданные методы и увидим, как работают объекты:


Cat cat1 = new Cat("Jabba");
Cat cat2 = new Cat("Leia");

cat1.getName();    // Returns Jabba
cat2.getName();    // Returns Leia
messWithCat(cat1);
changeKitty(cat2);
Cat cat3 = haveKitten();
cat1.getName();    // Returns Jabba – Note that object remains unchanged!
cat2.getName();    // Returns Wookie
cat3.getName();    // Returns Luke
Реклама